Pylablib Readthedocs Io en Latest
Pylablib Readthedocs Io en Latest
Release 1.4.3
Alexey Shkarin
1 Related projects 3
2 Citation 5
2.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2.2 Devices overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 Data processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
2.4 Data storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
2.5 Various utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
2.6 Change log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
2.7 pylablib . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
Index 1041
i
ii
pylablib Documentation, Release 1.4.3
PyLabLib aims to provide support for device control and experiment automation. It interfaces with lots of different
devices, including several different camera interfaces, translational stages, oscilloscopes, AWGs, sensors, and more.
The interface is implemented in a natural way through Python objects, and is easy to understand. For example, here
is a complete script which steps Thorlabs KDC101 stage by 10000 steps ten times, and each time grabs a frame with
Andor iXon camera:
Note: This is documentation for the newer 1.x version of the library. The older 0.x documentation can be found at
https://pylablib-v0.readthedocs.io/en/latest/ .
CONTENTS: 1
pylablib Documentation, Release 1.4.3
2 CONTENTS:
CHAPTER
ONE
RELATED PROJECTS
Pylablib cam-control - software for universal camera control and camera data acquisition.
3
pylablib Documentation, Release 1.4.3
TWO
CITATION
If you found this package useful in your scientific work, you can cite via Zenodo either referencing to the package in
general using the DOI 10.5281/zenodo.7324875, or to a specific version, as found on the Zenodo page.
2.1 Installation
If you already have it installed, you can upgrade it to get the newest version:
This will install the full set of dependencies: basic dependencies and computing packages (numpy, scipy,
pandas, numba, rpyc), basic device communication packages (pyft232, pyvisa, pyserial, pyusb), and PyQt5-
based GUI (pyqt5 and pyqtgraph). You can also install additional device library dependencies (nidaqmx and
websocket-client) using the extra requirements feature of pip:
In case you do not want some of these packages installed, or they are unavailable on your platform, you can install a
lightweight version of pylablib called pylablib-lightweight. It contains exactly the same code, but has only the
most basic dependencies (numpy, scipy, and pandas):
With this, the basic functionality (such as data processing or file IO) will work, but more advanced features such as
device communication and GUI, will require additional packages. In most cases, the raised errors will notify which
packages are missing. These can be installed either manually, or using the extra requirements:
• [extra] extra packages used in some situations: numba (speeds up some data processing) and rpyc (commu-
nication between different PCs)
• [devio] basic devio packages: pyft232, pyvisa, pyserial, and pyusb
• [devio-extra] additional devio packages: nidaqmx and websocket-client
5
pylablib Documentation, Release 1.4.3
• [gui-pyqt5] PyQt5-based GUI: pyqt5 and pyqtgraph. Should not be used together with [gui-pyside2]
• [gui-pyside2] PySide2-based GUI: pyside2 and pyqtgraph. Should not be used together with
[gui-pyqt5]
The options can be combined. For example,
installs the dependencies as the usual pylablib distribution, but with PySide2 Qt5 backend instead of PyQt5.
The package is also available on Anaconda via conda-forge channel. To install it, run
2.1.4 Usage
The basic package dependencies are NumPy for basic computations and overall array interface, SciPy for advanced
computations (interpolation, optimization, special functions), and pandas for heterogeneous tables (DataFrame). In
addition, it is recommended to have Numba package to speed up some computations. Finally, if you use options for
remote computing and communication between different PCs, you need to install RPyC. Note that when installed
directly from pip, numpy comes with the OpenBLAS version of the linear algebra library; if other version (e.g., Intel
MKL) is preferred, it is a good idea to have numpy already installed before installing pylablib.
The main device communication packages are PyVISA and pySerial, which cover the majority of devices. Several
devices (e.g., Thorlabs Kinesis and Attocube ANC 350) require additional communication packages: pyft232 and
6 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
PyUSB. Finally, some particular devices completely or partially rely on specific packages: NI-DAQmx for NIDAQ
and websocket-client for additional M2 Solstis functionality.
Finally, GUI and advanced multi-threading relies on Qt5, which has two possible options. The first (default) option is
PyQt5 with sip for some memory management functionality. Note that while newer PyQt5 versions >=5.11 already
come with PyQt5-sip, older versions require a separate sip installation. Hence, if you use an older PyQt5 version,
you need to install sip separately. The second possible Qt5 option is PySide2 with shiboken2. Both PyQt5 and PySide2
should work equally well, and the choice mostly depends on what is already installed, because having both PyQt5 and
PySide2 might lead to conflicts. Finally, plotting relies on pyqtgraph, which, starting with version 0.11m is compatible
with both PySide2 and PyQt5.
The package has been tested with Python 3.6 through 3.9, and is incompatible with Python 2. The last version officially
supporting Python 2.7 is 0.4.0. Furthermore, testing has been mostly performed on 64-bit Python. This is the recom-
mended option, as 32-bit version limitations (most notably, limited amount of accessible RAM) mean that it should
only be used when absolutely necessary, e.g., when some required packages or libraries are only available in 32-bit
version.
The most recent and extensive, but less tested and documented, version of this library is available on GitHub at https:
//github.com/AlexShkarin/pyLabLib/. There are several versions of installing it:
• Install using pip using GitHub as a library source:
• Download it as a zip-file and unpack it into any appropriate place (can be folder of the project you’re working
on, Python site-packages folder, or any folder added to PATH or PYTHONPATH variable).
To download the code of a specific version, you can choose it in the dropdown Branch menu under Tags tab. This
is the same code as available on PyPi.
Keep in mind that, unlike the first method, the required packages will not be automatically installed, so this has
to be done manually:
• Clone the repository to your computer In order to easily get updates in order to easily get updates. For that, you
need to install Git (https://git-scm.com/), and use the following commands in the command line (in the folder
where you want to store the library):
Whenever you want to update to the most recent version, simply type
git pull
in the library folder. Keep in mind that any changes that you make to the library code might conflict with the
new version that you pull from GitHub, so you should not modify anything in this folder if possible.
2.1. Installation 7
pylablib Documentation, Release 1.4.3
If you have any issues, suggestions, or feedback, you can either raise an issue on GitHub at https://github.com/
AlexShkarin/pyLabLib/issues, or send an e-mail to [email protected].
8 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
– Thorlabs Elliptec: resonant piezoelectric Thorlabs stages. Tested with ELL18 and ELL14 rotational
mounts.
– Newport Picomotor: precision piezo-actuated screws based on slip-stick principle. Tested with Newport
8742 Picomotor driver using Ethernet or USB connection.
– Arcus Performax: fairly common single- and multi-axis motor controllers sold under different brands:
Arcus, Nippon Pulse America, or Newmark Systems. Tested with PMX-4EX device with USB connection.
– Trinamic: universal motor controllers and drivers. Tested with a single-axis TMCM-1110 controller with
USB connection.
– Standa: Standa motorized positioners. Tested with a 8SMC4-USB single-axis controller and 8MT167-25
stepper motor stage.
– SmarAct: high-performance piezo sliders. Currently simple open-loop SCU controllers and MCS2 con-
trollers are supported. Tested with a standard HCU controller unit and an MCS2 controller with several
SLx stages.
– Physik Instrumente: piezo controllers. So far only PI E-515 and PI E-516 is supported and tested.
• Basic sensors
– HighFinesse: laser wavelength meters. Tested with WS6 and WS7 USB-controlled devices.
– Ophir: optical power and energy meters. Tested with Ophir Vega.
– Thorlabs: optical power and energy meters. Tested with PM160.
– Lakeshore: temperature sensors. Tested with Lakeshore 218.
– Cryocon: temperature sensors. Tested with CryoCon 14C.
– Cryomagnetics: liquid nitrogen or helium level sensor. Tested with LM-500 and LM-510 sensors.
– Pfeiffer: pressure gauges. Tested with TPG261 and DPG202 controllers.
– Leybold: pressure gauges. Tested with ITR90 gauge.
– Kurt J. Lesker: pressure gauges. Tested with KJL300 gauge.
– Agilent: pressure gauges. Tested with XGS-600 controller and FRG700 gauge.
– Thorlabs quadrature detector controller. Tested with TPA101.
– Keithley multimeters. Tested with model 2110.
– Voltcraft multimeters. Tested with VC-7055BT and VC880.
• Lasers
– Basic lasers
∗ Lighthouse Photonics SproutG
∗ Laser Quantum Finesse
– M2 Solstis laser and external mixing module
– Toptica iBeam Smart laser
– Hubner Cobolot
– Sirah Matisse laser
– NKT Photonics lasers
• Tektronix oscilloscopes. Tested with TDS2002B, TDS2004B, and DPO2004B.
The devices are represented as Python objects. In most cases, one object controls one device, although sometimes one
object can be responsible for multiple interconnected devices (e.g., when daisy-chaining of several devices is used, as
in Picomotor stage). All the device control functions are contained within the class. Occasionally, there are auxiliary
function present for listing available devices, dealing with data generated by the device, or adjusting global parameters.
Note: Some specific devices functionality might not be completely covered in the current release. If this is the
case for your device, you can let the developers know by raising an issue on GitHub, or sending an e-mail to py-
[email protected].
Connection
The device identifier or address needs to be provided upon the device object creation, after which it is automatically
connected. Getting the address usually depends on the kind of device:
• Simple message-style devices, such as AWG, oscilloscopes, sensors and gauges, require an address which
depends on the exact connection protocol. For example, serial devices addresses look like "COM1" (or "/
dev/ttyUSB0" or Linux), Visa addresses as "USB0::0x1313::0x8070::000000::INSTR", and network ad-
dresses take IP and, possibly, port "192.168.1.3:7230". To get the list of all connected devices, you can run
comm_backend.list_backend_resources():
10 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
('USB0::0x1313::0x8070::000000::INSTR',
'ASRL1::INSTR',
'ASRL3::INSTR',
'ASRL10::INSTR',
'ASRL36::INSTR',
'ASRL38::INSTR')
Network devices do not easily provide such functionality (and there are, in principle, many unrelated devices
connected to the network), so you might need to learn the device IP elsewhere. Usually, it is set on the device
front panel or using some kind of configuration tool and a different connection, such as serial or USB.
In most cases, the connection address is all you need. However, sometimes the connection might require some
additional information. The most common situations are ports for the network connection and baud rates for
the serial connections. Ports can be supplied either as a part of the string "192.168.1.3:7230", or as a tuple
("192.168.1.3", 7230). The baud rates are, similarly, provided as a tuple: ("COM1", 19200). By default,
the devices would use the baud rate which is most common for them, but in some cases (e.g., if the device baud
rate can be changed), you might need to provide it explicitly. If it is provided incorrectly, then no communication
can be done, and requests will typically return a timeout error:
>> meter.get_power() # let us assume that the devices is currently set up with␣
˓→38400 baud
...
OphirBackendError: backend exception: 'timeout during read'
>> meter.close() # need to close the connection before reopening
>> meter = Ophir.VegaPowerMeter(("COM3",38400)) # explicitly specifying the␣
˓→correct baud rate
>> meter.get_power()
1E-6
• More complicated devices using custom DLLs (usually cameras or some translation stages) will have more unique
methods of addressing individual devices: serial number, device index, device ID, etc. In most cases such devices
come with list_devices or get_devices_number functions, which give the necessary information.
After communication is done, the connection needs to be closed, since in most cases it can only be opened in one
program or part of the script at a time. It also implies that usually it’s impossible to connect to the device while its
manufacturer software is still running.
The devices have open and close methods, but they can also work in together with Python with statements:
wheel.close()
(continues on next page)
# a better approach
with Thorlabs.FW("COM1") as wheel: # connection is closed automatically when leaving the␣
˓→with-block
wheel.set_position(1)
Because the devices are automatically connected on creation, open method is almost never called explicitly. It is
generally only used to reconnect to the device after the connection has been previously closed, although in this case
creating a new device object would work just as well.
Operation
The devices are controlled by calling their methods; attributes and properties are very rarely used. Effort is made to
maintain consistent naming conventions, e.g., most getter-methods will start with get_ and setter methods with set_
or setup_ (depending on the complexity of the method). It is also common for setter methods to return the new value
as a result, which is useful in CLI operation and debugging. Devices of the same kind have the same names for similar
or identical functions: most stages have move_by, jog and stop methods, and cameras have wait_for_frame and
read_multiple_images methods. Whenever it makes sense, these methods will also have the same signatures.
For simplicity of usage and construction, devices interfaces are designed to be synchronous and single-threaded. Asyn-
chronous operation can be achieved by explicit usage of Python multi-threading. Furthermore, the device classes are
not designed to be thread safe, i.e., it is not recommended to use the same device simultaneously from two separate
threads. However, non-simultaneous calling of device methods from different threads (synchronized, e.g., using locks)
or simultaneous usage of several separate devices of the same class is supported.
Error handling
Errors raised by the devices are usually specific to the device and manufacturer, e.g., AttocubeError or
TrinamicError. These can be obtained from the module containing the device class, or from the class itself as
Error attribute:
All of the device errors inherit from DeviceError, which in turn is a subclass of RuntimeError. Therefore, one can
also use those exception classes instead:
12 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
A lot of information about the devices can be gained just from their method names and descriptions (docstrings). There
are several ways of getting these:
• In many cases your IDE (PyCharm, Spyder, VS Code with installed Python extension) supports code inspection.
In this case, the list of methods will usually pop up after you time the device object name and a dot (such as cam.),
and the method docstring will show up after you type the method name and parenthesis (such as cam.get_roi().
However, sometimes it might take a while for these pop-ups to show up.
• You can use console, such as Jupyter QtConsole, Jupyter Notebook, or a similar console built into the IDE. Here
the list of methods can be obtained using the autocomplete feature: type name of the class or object with a dot
(such as cam.) and then press Tab. The list of all methods should appear. To get the description of a particular
class or method, type it with a question mark (such as cam? or cam.get_roi?) and execute the result (Enter
or Shift-Enter, depending on the console). A description should appear with the argument names and the
description.
• You can also use the auto-generated documentation within this manual through the search bar: simply type the
name of the class or the method (such as AndorSDK3Camera or AndorSDK3Camera.get_roi) and look through
the results. However, the formatting of the auto-generated documentation might be a bit overwhelming.
All devices have get_settings and apply_settings methods which, correspondingly, return Python dictionaries
with the most common settings or take these dictionaries and apply the contained settings. These can be used to easily
store and re-apply device configuration within a script.
Additionally, there is get_full_info method, which returns as complete information as possible. It is particularly
useful to check the device status and see if it is connected and working properly, and to save the devices configuration
when acquiring the data. Finally, the settings can also be accessed through .dv attribute, which provides dictionary-like
interface:
By default not all information is shown, as it can take long time (up to several seconds) to obtain it, and it takes a lot of
space on the screen. To get a full set of parameters, you can call get_full_info("all"):
Many devices require external software not provided with this package.
The simpler devices using serial connection (either with an external USB-to-Serial adapter, or with a similar built-in
chip) only need the corresponding drivers: either standard adapter drivers or the ones supplied by the manufacturer,
e.g., via Thorlabs APT software. If the device already shows up as a serial communication port in the OS, no additional
software is normally needed. Similarly, devices using Ethernet connection do not need any external software, as long
as they are properly connected to the network. Finally, devices using Visa connection require NI VISA Runtime, which
is freely available from the National Instruments website. See also PyVISA documentation for details.
Devices which require manufacturer DLLs are harder to set up. For most of them, at the very least, you need to
install the manufacturer-provided software for communication. Frequently it already includes the necessary libraries,
which means that nothing else is required. However, sometimes you would need to download either an additional SDK
package, or DLLs directly from the website. Since these libraries take a lot of space and are often proprietary, they are
not distributed with the pylablib.
14 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Note that DLLs can have 32-bit and 64-bit version, and this version should agree with the Python version that you use.
Unless you have a really good reason to do otherwise, it is strongly recommended to use 64-bit Python, which means
that you would need 64-bit DLLs, which is the standard in most cases these days. To check your Python bitness, you
can read the prompt when running the Python console, or run python -c "import platform; print(platform.
architecture()[0])" in the command line.
In addition, you need to provide pylablib with the path to the DLLs. In many cases it checks the standard locations such
as the default System32 folder (used, e.g., in DCAM or IMAQ cameras), paths contained on the PATH environment
variable, or defaults paths for manufacturer software (such as C:/Program Files/Andor SOLIS for Andor cameras).
If the software path is different, or if you choose to obtain DLLs elsewhere, you can also explicitly provide path by
setting the library parameter:
All of these requirements are described in detail for the specific devices.
Starting from Python 3.8 the DLL search path is changed to not include the files contained in PATH environment
variable and in the script folder. By default, this behavior is still emulated when pylablib searches for the DLLs, since
it is required in some cases (e.g., Photon Focus pfcam interface). If needed, it can be turned off (i.e., switched to the
new default behavior of Python 3.8+) by setting pll.par["devices/dlls/add_environ_paths"]=False.
Advanced examples
Connecting to a Cryomagnetics LM500 level meter and reading out the level at the first channel:
Stepping the M Squared laser wavelength and recording an image from the Andor iXon camera at each step:
Available devices
• Cameras
– Andor SDK2 and Andor SDK3: variety of Andor (currently part of Oxford Instruments) cameras. Tested
with Andor iXon, Luca, Newton, Zyla, Neo and Marana.
– Allied Vision Bonito cameras: CameraLink-interfaced cameras. Tested with Bonito CL-400B/C and NI
IMAQ frame grabber.
– Basler: Basler pylon-compatible cameras. Tested with an emulated Basler camera.
– BitFlow: BitFlow Axion family frame grabbers. Tested with BitFlow Axion 1xB frame grabber together
with PhotonFocus MV-D1024E camera.
– DCAM: Hamamatsu cameras. Tested with Hamamatsu Orca Flash 4.0 and ImagEM.
– NI IMAQ: National Instruments frame grabbers. Tested with NI PCI-1430 and PCI-1433 frame grabbers
together with PhotonFocus MV-D1024E camera.
– NI IMAQdx: National Instruments universal camera interface. Tested with Ethernet-connected PhotonFo-
cus HD1-D1312 camera.
– Photon Focus: Photon Focus pfcam interface. Tested with PhotonFocus MV-D1024E camera connected
through either NI frame grabbers (PCI-1430 and PCI-1433) or Silicon Software frame grabbers (microEn-
able IV AD4-CL).
– PCO SC2: PCO cameras. Tested with pco.edge cameras with CLHS and regular CameraLink interfaces,
and with pco.pixelfly usb cameras.
– Picam: Princeton Instruments cameras. Tested with a PIXIS 400 camera.
– PVCAM: Photometrics cameras. Tested with a Prime 95B camera.
– Silicon Software: Silicon Software frame grabbers. Tested with microEnable IV AD4-CL frame grabbers
together with PhotonFocus MV-D1024E camera.
– Thorlabs Scientific Cameras: Thorlabs sCMOS cameras. Tested with Thorlabs Kiralux camera.
– Uc480/uEye: multiple cameras, including simple Thorlabs and IDS cameras. Tested with IDS
SC2592R12M and Thorlabs DCC1545M.
– Mightex: several different USB camera types with different APIs. Implemented and tested only for S-series
cameras.
• Stages
– Attocube ANC300 and Attocube ANC350: most common Attocube positioner controllers. Tested with
Ethernet and USB connection for ANC300, and USB connection for ANC350.
– Thorlabs APT/Kinesis: basic Thorlabs motorized stages and optomechanics devices. Tested with KDC101,
K10CR1, and BSC201 motor controllers, KIM101 piezo motor controller, KPZ101 piezo controllers, as
well as MFF101 and FW102 (described at a different page)
– Thorlabs Elliptec: resonant piezoelectric Thorlabs stages. Tested with ELL18 and ELL14 rotational
mounts.
– Newport Picomotor: precision piezo-actuated screws based on slip-stick principle. Tested with Newport
8742 Picomotor driver using Ethernet or USB connection.
– Arcus Performax: fairly common single- and multi-axis motor controllers sold under different brands:
Arcus, Nippon Pulse America, or Newmark Systems. Tested with PMX-4EX device with USB connection.
– Trinamic: universal motor controllers and drivers. Tested with a single-axis TMCM-1110 controller with
USB connection.
16 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
– Standa: Standa motorized positioners. Tested with a 8SMC4-USB single-axis controller and 8MT167-25
stepper motor stage.
– SmarAct: high-performance piezo sliders. Currently simple open-loop SCU controllers and MCS2 con-
trollers are supported. Tested with a standard HCU controller unit and an MCS2 controller with several
SLx stages.
– Physik Instrumente: piezo controllers. So far only PI E-515 and PI E-516 is supported and tested.
• Basic sensors
– HighFinesse: laser wavelength meters. Tested with WS6 and WS7 USB-controlled devices.
– Ophir: optical power and energy meters. Tested with Ophir Vega.
– Thorlabs: optical power and energy meters. Tested with PM160.
– Lakeshore: temperature sensors. Tested with Lakeshore 218.
– Cryocon: temperature sensors. Tested with CryoCon 14C.
– Cryomagnetics: liquid nitrogen or helium level sensor. Tested with LM-500 and LM-510 sensors.
– Pfeiffer: pressure gauges. Tested with TPG261 and DPG202 controllers.
– Leybold: pressure gauges. Tested with ITR90 gauge.
– Kurt J. Lesker: pressure gauges. Tested with KJL300 gauge.
– Agilent: pressure gauges. Tested with XGS-600 controller and FRG700 gauge.
– Thorlabs quadrature detector controller. Tested with TPA101.
– Keithley multimeters. Tested with model 2110.
– Voltcraft multimeters. Tested with VC-7055BT and VC880.
• Lasers
– Basic lasers
∗ Lighthouse Photonics SproutG
∗ Laser Quantum Finesse
– M2 Solstis laser and external mixing module
– Toptica iBeam Smart laser
– Hubner Cobolot
– Sirah Matisse laser
– NKT Photonics lasers
• Tektronix oscilloscopes. Tested with TDS2002B, TDS2004B, and DPO2004B.
• NI DAQs. Tested with NI USB-6008, NI USB-6343, and NI PCIe-6323.
• Generic AWGs. Tested with Agilent 33500 and 33220A, Rigol DG1022, Tektronix AFG1022, GW Instek
AFG2225 and AFG2115, and RS Comp AFG21005.
• Andor spectrographs. Tested with Kymera 328i spectrograph connected via an Andor Newton camera through
I2C interface.
• Miscellaneous Thorlabs devices: MFF101/102 motorized flip mirror mount, FW102/212 motorized filter wheel,
and MDT693/694 high-voltage source.
• Miscellaneous OZOptics devices: EPC04 fiber polarization controller, DD100 motorized fiber attenuator, and
TF100 motorized fiber filter.
• Lumel devices: RE72 temperature controller
• Miscellaneous devices
– Conrad relay board
– Basic Arduino communication
– ElektroAutomatik power supplies
– Rigol power supplies
• Generic Windows devices
• Mid-level protocols
– Modbus
2.2.2 Cameras
18 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
• Mightex: several different USB camera types with different APIs. Implemented and tested only for S-series
cameras.
Note: General device communication concepts are described on the corresponding page.
Basic examples
In case you need to grab and process frames continuously, the example is a bit more complicated:
Basic concepts
Frames buffer
In most cases, the frames acquired by the camera are first temporarily stored in the local camera and / or frame grabber
memory, from which they are transferred to the PC RAM by the camera drivers. Afterwards, this memory is made
available to all other applications. In principle, it should be enough to store only the most recent frame in RAM, and
for the user software to continuously wait for a new frame, immediately read it from RAM and process it. However,
such approach is very demanding to the user code: if the new frame is acquired before the previous one is processed
or copied, then the RAM data is overwritten, and the old frame is lost. Hence, it is more practical to have a buffer of
several most recently acquired frames to account for inevitable interruptions in the user wait-read-process loop caused
by OS scheduling and by other jobs. In this case, the frames get lost only when the buffer is completely filled, and the
oldest frames starts getting overwritten.
When using the camera classes provided by pylablib, you do not need to worry about setting up the buffer yourself,
since it is done behind the scene either by the manufacturer’s code or by the device class. However, it is important to
keep in mind the existence of the buffer when setting up the acquisition, interpreting the buffer and acquired frames
status, or identifying the skipped frames.
The size of the buffer can almost always be selected by the user. Typically it is a good idea to have at least 100ms worth
of frames there, although, depending on the other jobs performed by the software, it can be larger.
Acquisition setup
Setting up an acquisition process might take a lot of time (up to 10s in more extreme cases). This happens mostly
because of the buffer allocation and setting up internal API structures; initiating the acquisition process itself is fairly
fast. Hence, it is useful to separate setting up / cleaning up and starting / stopping.
The first two procedures correspond to setup_acquisition and clear_acquisition method, which are slow, but
rarely called. Usually, they only need to be invoked right after connecting to the camera, or when the acquired image
size is changed (e.g., due to a change in binning or ROI). Since these methods deal with buffer allocation, in almost all
cases they take a parameter specifying buffer size (typically called nframes).
The other two procedures correspond to start_acquisition and stop_acquisition methods. These try to be as
fast as possible, as they need to be called any time the acquisition is started or stopped, or when minor parameters
(frame rate, exposure, trigger mode) are called.
Most cameras allow the user to select only a part of the whole sensor for readout and transfer. Since the readout speed
is usually the factor limiting the frame rate, selecting smaller ROI frequently lets you achieve higher frame rate. In
addition, it also reduces the size of the frame buffer and the data transfer load. Same goes for binning: many cameras
can combine values of several consecutive pixels in the same row or column (or both), which results in smaller images
and, depending on the camera architecture, higher signal-to-noise ratio compared to binning in post-processing. Much
less frequently you can set up subsampling instead of binning, which skips pixels instead of averaging them together.
Both operations depend very strongly on the exact hardware, so there are typically many associated restriction. The
most common are minimal sizes in width and height, positions and sizes being factors of some power of 2 (up to 32
for some cameras), or equal binning for both axes. Device classes will typically round the ROI to the nearest allowed
value. Furthermore, the scaling of the maximal frame rate with the ROI size is also hardware-dependent; for example,
in many sCMOS chips readout speed only depends on the vertical extent, since the readout is done simultaneously for
the whole row. In most cases, it takes some experiments to get a hang of the camera behavior.
Almost all scientific cameras let user change the exposure, typically in a wide range (down to sub-ms). Frequently
they also allow to separately change the frame period (inverse of the frame rate). Usually (but not always) the minimal
frame period is set by the exposure plus some readout time, which depends on the ROI and some additional parameters
such as pixel clock or simultaneous readout mode. Usually exposure takes priority over the frame period, i.e., if the
frame period is set too short, it is automatically adjusted. Notable exception from this rule is Uc480 interface, where
this dependence in reversed.
Triggering
Usually the cameras will have several different options for triggering, i.e., choosing when to start acquiring a new frame
or a new batch of frames. The default option is the internal trigger, which means that the internal timer generates trigger
event at a constant rate (frame rate). Many cameras will also take an external trigger signal to synchronize acquisition
to external events or other cameras. Typically, a rising edge from 0 to 5V on the input will initiate the frame acquisition,
but more exotic options (different polarities or levels, exposure control with pulse width, line-readout trigger) can be
present.
20 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Here we talk more practically about performing tasks common to most cameras.
Simple acquisition
Frame acquisition is, understandably, the most important part of the camera. Basic acquisition can be done without
explicitly setting up the acquisition loop, simply by using ICamera.snap() and ICamera.grab() methods which,
correspondingly, grab a single frame or a given number of frames:
These allow for quick tests of whether the camera works properly, and for occasional frames acquisition. However,
these methods have to start and stop acquisition every time they are called, which for some cameras can take about a
second. Hence, if continuous acquisition and high frame rate are required, you would need to set up the acquisition
loop.
Acquisition loop
# nframes=100 relates to the size of the frame buffer; the acquisition will continue␣
˓→indefinitely
cam.start_acquisition()
while True: # acquisition loop
cam.wait_for_frame() # wait for the next available frame
frame = cam.read_oldest_image() # get the oldest image which hasn't been read yet
# ... process frame ...
if time_to_stop:
break
cam.stop_acquisition()
It relies on 3 sets of methods. First, starting and stopping acquisition using start_acquisition and
stop_acquisition. As explained above, one also has an option to setup the acquisition first using
setup_acquisition, which makes the subsequent start_acquisition call faster. However, one can also sup-
ply the same setup parameters to start_acquisition method, which automatically sets up the acquisition if it is not
set up yet, or if any parameters are different from the current ones.
Second are the methods for checking on the acquisition process. The method used above is wait_for_frame, which
by default waits until there is at least one unread frame in the buffer (i.e., it exits immediately if there is already a frame
available). Its arguments modify this behavior by changing the point from which the new frame is acquired (e.g., from
the current call), or the minimal required number of frames. Alternatively, there is a method get_new_images_range,
which returns a range of the frame indices which have been acquired but not read. This method allows for a quick check
of a number of unread frames without pausing the acquisition.
Finally, there are methods for reading out the frames. The simplest method is read_oldest_image, which return
the oldest image which hasn’t been read yet, and marks it as read. A more powerful is the read_multiple_images
method, which can return a range of images (by default, all unread images). Both of these methods also take a peek
argument, which allows one to read the frames without marking them as read.
ICamera.read_multiple_images() method described above has several different formats for returning the frames,
which can be controlled using ICamera.set_frame_format() and checked ICamera.get_frame_format(). The
default format is "list", which returns a list of individual frames. The second possibility is "array", which returns
a single 3D numpy array with all the frames. Finally, "chunks" returns a list of 3D arrays, each containing several
consecutive frames.
While "chunks" format is the hardest to work with, it provides the best performance. First, it does not require any extra
memory copies, which negatively affect performance at very high data rates, above ~1Gb/s. Second, it can combine
multiple small frames together into a single array, which makes further processing faster, as it does require explicit
Python loop over every frame. This usually becomes important at frames rates above ~10kFPS, where treating each
frame as an individual 2D array leads to significant overhead.
Frame indexing
Different areas and libraries adopt different indexing convention for 2D arrays. The two most common ones are
coordinate-like xy (the first index is the x coordinate, the second is y coordinate, and the origin is in the lower left
corner) and matrix-like ij (the first index is row, the second index is column, the origin is int the upper right corner).
Almost all cameras adopt the ij convention. The only exception is Andor SDK2, which uses similar row-column
indexing, but counting from the bottom.
By default, the frames returned by the camera are indexed in the preferred convention, to reduce the overhead on
re-indexing the frames. It is possible to check and change it using ICamera.get_image_indexing() and ICamera.
set_image_indexing() methods:
Both ROI and binning are controlled by one pair of methods get_roi and set_roi which, depending on whether
camera supports binning, take (and return) 4 or 6 arguments: start and stop positions of ROI along both axes and,
optionally, binning along the axes:
cam.set_roi(0,128) # set roi with 128px width and full height (non-supplied arguments␣
˓→take extreme values)
cam.set_roi(0,128,0,128,2,2) # set 128x128px ROI with 2x2 binning; the resulting image␣
˓→size is 64x64
Regardless of the frame indexing, the first pair of arguments always controls horizontal span, the second pair controls
vertical span, and the last pair controls horizontal and vertical binning (if applicable).
22 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
In addition, there is a couple of methods to acquire the detector and frame size. The first method is
get_detector_size. It always returns the full camera detector size as a tuple (width, height) and, therefore,
is not affected by ROI, binning, and indexing. The second method is get_data_dimensions, which returns the shape
of the returned frame given the currently set up indexing. The results of this method do depend on the ROI, binning,
and indexing:
>> cam.set_image_indexing("xyb")
>> cam.get_detector_size() # unaffected
(2560, 1920)
>> cam.get_data_dimensions() # depends on indexing
(128, 64)
>> cam.get_frame_timings() # frame period is a usually bit larger due to the readout␣
˓→time
TAcqTimings(exposure=0.1, frame_period=0.12)
>> cam.set_exposure(0.01)
>> cam.get_frame_timings() # smaller exposure is still compatible with this frame period
TAcqTimings(exposure=0.01, frame_period=0.12)
>> cam.set_frame_period(0) # effectively means "set the highest possible frame rate"
>> cam.get_frame_timings()
TAcqTimings(exposure=0.01, frame_period=0.03)
>> cam.set_exposure(0.2)
>> cam.get_frame_timings() # frame period is increased accordingly
TAcqTimings(exposure=0.2, frame_period=0.22)
There are exceptions for some camera types, which are discussed separately.
Camera attributes
Some camera interfaces, e.g., Thorlabs Scientific Cameras, PCO SC2, or NI IMAQ are fairly specific, and only apply
to a handful of devices with very similar capabilities. In this case, pylablib usually attempts to implement as much of
the functionality as possible given the available hardware, and to present it via the camera object methods.
In other cases, e.g., NI IMAQdx, Andor SDK3, or DCAM, the same interface deals with many fairly different cameras.
This is especially true for IMAQdx, which covers hundreds of cameras from dozens of manufacturers, all with very
different capabilities and purpose. Since managing such cameras can not usually be conformed to a small set of func-
tions, it is implemented through camera attributes mechanism. That is, for each camera the interface defines a set of
attributes (sometimes also called properties or features), which can be queried or set by their names, and whose exact
meaning and possible values depend on the specific camera.
Typically, cameras dealing with attributes will implement IAttributeCamera.get_attribute_value() and
IAttributeCamera.set_attribute_value() for querying and setting the attributes, as well as dictionary-like .
cav (stands for “camera attribute value”) interface to do the same thing:
0.1
Note that, depending on the camera, the attribute properties (especially minimal and maximal value) can depend on
the other camera attributes. For example, minimal exposure can depend on the frame size:
24 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
If the documentation is not available (as is the case for, e.g., some IMAQdx cameras), the best way to learn about the
attributes is to use the native software (whenever available) to modify camera settings and then check how the attributes
change. Besides that, it is always useful to check attribute description (available for IMAQdx parameter), their range,
and the available values for enum attributes.
Trigger setup
The trigger is usually set up using set_trigger_mode method, although it might be different if more specialized
modes are used. When external trigger is involved, most of the code (such as acquisition set up and start) stays the
same. The only difference is the rate at which the frames are generated:
Frame metainfo
Many cameras supply additional information together with the frames. Most frequently it contains the internal frames-
tamp and timestamp (which are useful for tracking missing frames), but sometimes it also includes additional informa-
tion such as frame size or location, status, or auxiliary input bits. To get this information, you can supply the argument
return_info=True to the read_multiple_images method. In this case, instead of a single list of frames, it will
return a tuple of two lists, where the second list contains this metainfo.
There are several slightly different metainfo formats, which can be set using ICamera.set_frame_info_format()
method. The default representation is a (possibly nested) named tuple, but it is also possible to represent it as a flat list,
flat dictionary, or a numpy array. The exact structure and values depend on the camera.
Keep in mind, that for some camera interfaces (e.g., Uc480 or Silicon Software) obtaining the additional information
might take relatively long, even longer than the proper frame readout. Hence, at higher frame rates it might become a
bottleneck, and would need to be turned off.
Related projects
Pylablib cam-control is a standalone software package which builds on camera classes included in pylablib. It provides
an easy way to detect and control many different cameras and acquire their data. In addition, it supports custom on-line
image processing, flexible data acquisition, and control by external software using a TCP/IP server.
• Andor SDK2 and Andor SDK3: variety of Andor (currently part of Oxford Instruments) cameras. Tested with
Andor iXon, Luca, Newton, Zyla, Neo and Marana.
• Allied Vision Bonito cameras: CameraLink-interfaced cameras. Tested with Bonito CL-400B/C and NI IMAQ
frame grabber.
• Basler: Basler pylon-compatible cameras. Tested with an emulated Basler camera.
• BitFlow: BitFlow Axion family frame grabbers. Tested with BitFlow Axion 1xB frame grabber together with
PhotonFocus MV-D1024E camera.
• DCAM: Hamamatsu cameras. Tested with Hamamatsu Orca Flash 4.0 and ImagEM.
• NI IMAQ: National Instruments frame grabbers. Tested with NI PCI-1430 and PCI-1433 frame grabbers together
with PhotonFocus MV-D1024E camera.
• NI IMAQdx: National Instruments universal camera interface. Tested with Ethernet-connected PhotonFocus
HD1-D1312 camera.
• Photon Focus: Photon Focus pfcam interface. Tested with PhotonFocus MV-D1024E camera connected through
either NI frame grabbers (PCI-1430 and PCI-1433) or Silicon Software frame grabbers (microEnable IV AD4-
CL).
• PCO SC2: PCO cameras. Tested with pco.edge cameras with CLHS and regular CameraLink interfaces, and
with pco.pixelfly usb cameras.
• Picam: Princeton Instruments cameras. Tested with a PIXIS 400 camera.
• PVCAM: Photometrics cameras. Tested with a Prime 95B camera.
• Silicon Software: Silicon Software frame grabbers. Tested with microEnable IV AD4-CL frame grabbers to-
gether with PhotonFocus MV-D1024E camera.
• Thorlabs Scientific Cameras: Thorlabs sCMOS cameras. Tested with Thorlabs Kiralux camera.
• Uc480/uEye: multiple cameras, including simple Thorlabs and IDS cameras. Tested with IDS SC2592R12M
and Thorlabs DCC1545M.
• Mightex: several different USB camera types with different APIs. Implemented and tested only for S-series
cameras.
Note: General camera communication concepts are described on the corresponding page
Andor cameras
Andor implements two completely separate interfaces for different cameras. The older one, called SDK2, or simply
SDK, provides interface for the older cameras: iXon, iKon, iStart, iDus, iVac, Luca, Newton. The details of this SDK
are available in the manual.
The newer SDK, called SDK3, covers newer cameras: Zyla, Neo, Apogee, Sona, Marana, and Balor. The manual
describes the cameras and capabilities in more details.
The required DLLs are distributed with Andor Solis or the corresponding Andor SKD. In most cases, you have Andor
Solis already installed to provide the drivers and to communicate with the cameras to begin with.
Andor SDK 2
This is an older SDK, which mainly involves older cameras. It has been tested with Andor iXon, Luca, and Newton.
The code is located in pylablib.devices.Andor, and the main camera class is pylablib.devices.Andor.
AndorSDK2Camera.
26 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
The required DLL can have different names depending on the Solis version and SDK bitness. For 64-bit version it
will be called atmcd64d.dll or atmcd64d_legacy.dll. For 32-bit version, correspondingly, atmcd32d.dll or
atmcd32d_legacy.dll. By default, library searches for DLLs in Andor Solis and Andor SDK folder in Program
Files folder (or Program files (x86), if 32-bit version of Python is running), as well as in the folder containing
the script. If the DLLs are located elsewhere, the path can be specified using the library parameter devices/dlls/
andor_sdk2:
Connection
The cameras are identified by their index, starting from zero. To get the total number of cameras, you can run Andor.
get_cameras_number_SDK2:
Warning: It is important to close all camera connections before finishing your script. Otherwise, DLL resources
might become permanently blocked, and the only way to solve it would be to restart the PC.
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI
and exposure, starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of
differences from the standard libraries worth highlighting:
• Since the manufacturer DLLs do not provide methods to get most of the camera parameters (such as exposure
or ROI), it is impossible to know them when connecting the camera. To get around it, the camera is put into a
“default” state any time the connection is opened.
• When applicable, it is important to properly set the cooling setpoint and the fan mode. By default, the fan is
turned off, and the cooling is set to the 20’th percentile of the whole range (e.g., -80C for Andor iXon). It is
possible to pass these parameters on camera creation:
• Often cameras have a lot of different readout parameters: channel, amplifier, vertical and horizontal scan speed,
etc. These parameters greatly affect the camera sensitivity and readout speed. Upon the connection, the pa-
rameter are typically set to the slowest mode. To get the list of all possible parameter combinations, you can
use AndorSDK2Camera.get_all_amp_modes() and AndorSDK2Camera.get_max_vsspeed(). Afterwards,
you can set them using AndorSDK2Camera.set_amp_mode() and AndorSDK2Camera.set_vsspeed().
• The default shutter parameter is "closed". This preserves camera from possible high illumination, but can lead
to confusion, if you expect to see some image.
• This SDK does not allow for specifying number of frames in the frames buffer. However, the parameters chosen
by the SDK are usually reasonable (at least a second worth of acquisition).
• Some cameras (e.g., iXon) have lots of readout (full frame, ROI, full vertical binning, etc.) and acquisition modes
(single, continuous, accumulating, kinetic cycle, etc.). They are described in details in the manual.
Andor SDK 3
This is a newer SDK, which covers the newer cameras. It has been tested with Andor Zyla, Neo and Marana.
The code is located in pylablib.devices.Andor, and the main camera class is pylablib.devices.Andor.
AndorSDK3Camera.
Software requirements
This library requires several DLLs all located in the same folder: atcore.dll, atblkbx.dll, atcl_bitflow.dll,
atdevapogee.dll, atdevregcam.dll, atusb_libusb.dll, atusb_libusb10.dll. Same as for SDK2, pylablib
looks for DLLs in Andor Solis and Andor SDK3 folders in Program Files folder (or Program files (x86), if
32-bit version of Python is running), as well as in the folder containing the script. A custom DLLs path can be specified
using the library parameter devices/dlls/andor_sdk3:
Connection
The cameras are identified by their index, starting from zero. To get the total number of cameras, you can run Andor.
get_cameras_number_SDK3:
28 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
The operation of these cameras is also relatively standard. They support all the standard methods for dealing with ROI
and exposure, starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of
differences from the standard libraries worth highlighting:
• The SDK also provides a universal interface for getting and setting various camera attributes (called “fea-
tures” in the documentation) using their name. You can use AndorSDK3Camera.get_attribute_value()
and AndorSDK3Camera.set_attribute_value() for that, as well as .cav attribute which gives a dictionary-
like access:
0.1
Some values serve as commands; these can be invoked using AndorSDK3Camera.call_command() method. To
see all available attributes, you can call AndorSDK3Camera.get_all_attributes() to get a dictionary with
attribute objects, and AndorSDK3Camera.get_all_attribute_values() to get the dictionary of attribute
values. The attribute objects provide additional information: their kind, whether they are implemented, readable,
or writable, what are their limits or possible values, etc:
Note: General camera communication concepts are described on the corresponding page.
Allied Vision manufactures a variety of cameras with different interfaces: USB, GigE, and CameraLink. Currently,
only CameraLink Bonito cameras using NI IMAQ frame grabber are supported. It has been tested with Bonito CL-
400B/C and NI IMAQ frame grabber.
The code is located in pylablib.devices.AlliedVision, and the main camera class is pylablib.devices.
AlliedVision.BonitoIMAQCamera.
Software requirements
Since the camera control is done purely through the frame grabber interface, the requirements are the same as for
generic IMAQ cameras. However, the correct camera file still needs to be specified to determine the correct serial
communication parameters (especially the termination character)
Connection
The cameras are identified by their name, which usually looks like "img0". To get the list of all cameras, you can use
NI MAX (Measurement and Automation Explorer), or IMAQ.list_cameras():
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI
and exposure, starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of
differences from the standard libraries worth highlighting:
• Bonito.BonitoIMAQCamera supports all of IMAQ.IMAQCamera features, such as trigger control and fast
buffer acquisition. Some methods have been modified to make them more convenient: e.g., Bonito.
BonitoIMAQCamera.set_roi() method sets the camera ROI and automatically adjusts the frame grabber ROI
to match.
• Internally the camera only supports vertical ROI (number of rows), so the horizontal ROI is set via the frame
grabber. This means that regardless of the horizontal ROI settings the whole rows are always transmitted between
the camera and the frame grabber, so it does not affect, e.g., the maximal frame rate.
• The camera supports a status line, which replaces the first 8 pixels in the upper row encoded frame number. You
can use AlliedVision.Bonito.get_status_lines() function to identify and extract the data in the status
lines from the supplied frames. Note that due to the full row transfer mentioned earlier, the status line is only
available if the horizontal ROI span starts from zero; otherwise, it will be partially or completely cut off.
• You can use the function AlliedVision.Bonito.check_grabber_association() to check if the given
IMAQ camera is a Bonito model by sending several standard Bonito commands and checking replies.
Note: General camera communication concepts are described on the corresponding page
30 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Basler manufactures a wide variety of cameras, which implement GenICam-based interface through its pylon API. It
has been tested with pylon-provided emulated camera.
The code is located in pylablib.devices.Basler, and the main camera class is pylablib.devices.Basler.
BaslerPylonCamera.
Software requirements
These cameras require PylonC_vX_Y.dll (where X and Y is the pylon version, e.g., PylonC_V7_1.dll), which is
installed with the freely available upon registration Basler pylon Camera Software Suite (the current latest version is
7.1.0). Note that the DLLs are contained in the pylon SDK, which is only included in the “developer” version of the suite,
and not in the “camera user” (default) version. After installation, the path to the DLL (for pylon 7.1.0 located by default
in Basler/pylon 7/Runtime/x64 folder in Program Files) is automatically added to system PATH variable, which
is one of the places where pylablib looks for it by default. If the DLLs are located elsewhere, the path (either to the
DLL file, or to the containing folder) can be specified using the library parameter devices/dlls/basler_pylon:
Connection
The cameras are identified either by their index among the present cameras (starting from 0), or by their name. To get
the list of all cameras, you can use pylon Viewer, or Basler.list_cameras:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI,
starting and stopping acquisition, and operating the frame reading loop. The SDK also provides a universal in-
terface for getting and setting various camera attributes using their name. You can use BaslerPylonCamera.
get_attribute_value() and BaslerPylonCamera.set_attribute_value() for that, as well as .cav attribute
which gives a dictionary-like access:
To see all available attributes, you can call BaslerPylonCamera.get_all_attributes() to get a dictionary with
attribute objects, and BaslerPylonCamera.get_all_attribute_values() to get the dictionary of attribute values.
The attribute objects provide additional information: attribute kind (integer, enum, string, etc.), range (either numerical
range, or selection of values for enum attributes), description string, etc.:
Since these properties vary a lot between different cameras, it is challenging to write a universal class covering a
large range of cameras. Hence, currently the universal class only has the basic camera parameter control such as ROI
(without binning), acquisition status, and exposure (if present). For many specific cameras you might need to explore
the attributes tree (either using the Python class and, e.g., a console, or via pylon Viewer) and operate them directly in
your code.
Known issues
• Currently only the basic unpacked monochrome pixel formats are supported: Mono8, Mono10, Mono12, Mono16,
and Mono32. The reason is that even nominally well-defined types (e.g., Mono12Packed) have different formats
for different cameras. Currently any unsupported format will raise an error on readout by default. It it still
possible to read these out as raw frame data in the form of 1D or 2D numpy 'u1' array by enabling raw frame
readout using BaslerPylonCamera.enable_raw_readout() method:
Note: General camera communication concepts are described on the corresponding page
32 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
BitFlow manufacturers several kinds of camera interface cards, including CameraLink. Currently, only newer Camer-
aLink Axion family is supported. It has been tested with NI BitFlow Axion 1xB frame grabbers together with Photon-
Focus MV-D1024E camera.
The code is located in pylablib.devices.BitFlow, and the main camera class is pylablib.devices.BitFlow.
BitFlowCamera.
Software requirements
This interfaces requires two pieces of software, both freely available on the BitFlow website. First, you need BitFlow
SDK 6.5, which also includes all the necessary drivers. The free version does not provide any headers and documen-
tation to the DLLs, so yo use it you also need to install the manufacturer-provided Python packages, either for Python
3.6.6, or for Python 3.8.10. Note that only these two Python versions are officially supported.
After installation, the DLL locations are automatically added to the PATH environment variable. To facilitate proper
package import and DLL loading on Python 3.8, it is recommended to install BitFlow SDK into its default library, or
at least leave BitFlow in the folder name.
Connection
The cameras are identified by their index, starting from 0. To get the list of all cameras, you can use BitFlow.
list_cameras():
Operation
Unlike most camera classes, the frame grabber interface only deals with the frame transfer between the camera and the
PC over the CameraLink interface. Therefore, in can not directly control camera parameters such as exposure, frame
rate, triggering, ROI, etc. Some similar-looking parameters are still present, but they have a different meaning:
• ROI is defined within the transferred image, whose size itself is determined by the camera ROI. Hence, e.g., if
the camera chip is 1024x1024px and its roi is 512x512, then the frame grabber ROI can go only up to 512x512.
Any attempts to set it higher result in the frozen acquisition, as the frame grabber expects a larger frame than it
receives, and waits forever to get the rest.
At high frame rates (above ~10kFPS) dealing with each frame individually becomes too slow for Python. Hence, there
is an option to read out and process frames in larger ‘chunks’, which are 3D numpy arrays with the first axis enumerating
the frame index. This approach leverages the ability to store several frame buffers in the contiguous memory locations
(resulting in a single 3D array), and it essentially eliminates the overhead for dealing with multiple frames at high frame
rates, as long as the total data rate is manageable (typically below 600Mb/s).
This option can be accessed by calling using BitFlowCamera.set_frame_format() method to set frames format to
"chunks". In this case, instead of a list of individual frames (which is the standard behavior), the method returns list
of chunks of varying size, which contain several consecutive frames.
On top of that, due to unavoidable Python loop required by the BitFlow Python interface, the frame rate is usually
limited to about 2-4kFPS. However, there is a way to overcome this by merging n consecutive frames to a single “super-
frame” with n times larger height. This merging can be specified by frame_merge parameter in the BitFlowCamera.
setup_acquisition() or BitFlowCamera.start_acquisition() methods (by default it is 1, meaning no merg-
ing). Adjusting the frame grabber ROI and splitting the resulting files is done transparently for the user; the only
difference is that frames always arrive in batches, e.g., with frame_merge=10 and 10FPS rate the frames will arrive
once a second in batches of 10. Therefore, it makes sense to adjust the merging to keep the “merged” frame rate high
enough for real-time operations but lower than the 2kFPS limit (e.g., around 100FPS).
The frame grabber needs some basic information about the camera: sensor size, bit depth, data transfer format, timeouts,
aux lines mapping, etc. This information is contained in the so-called camera files, which for Axion cameras have .
bfml extension. These files can be assigned to cameras using SysReg utility located in the Bin64 folder of your
BitFlow installation (by default, C:\BitFlow SDK 6.5\Bin64).
In addition, due to limitations of the provided Python interfaces, some operations such as changing ROI and bitness
can only be done by altering the camera file. Hence, there is an option to create a temporary camera file and alter it
to control these parameters. However, it needs the original camera file to serve as a template (this original file is only
used as source and not modified). Since there is no possibility to get a path to this file within the Python interface, it
should be provided using camfile parameter upon creation.
Known issues
• As mentioned above, ROI is defined within a frame transferred by the camera. Hence, if it includes pixels with
positions outside of the transferred frame, the acquisition will time out. For example, suppose the camera sensor
is 1024x1024px, and the camera ROI is selected to be central 512x512 region. As far as the frame grabber is
concerned, now the camera sensor size is 512x512px. Hence, if you try to set the same frame grabber ROI (i.e.,
512x512 starting at 256,256), it will expect at least 768x768px frame. Since the frame is, actually, 512x512px,
the acquisition will time out. The correct solution is to set frame grabber ROI from 0 to 512px on both axes. In
general, it is a good idea to always follow this pattern: control ROI only on camera, and always set frame grabber
ROI to cover the whole transfer frame.
Note: General camera communication concepts are described on the corresponding page.
DCAM is the interface used in Hamamatsu cameras. It has been tested with Hamamatsu Orca Flash and ImagEM.
The code is located in pylablib.devices.DCAM, and the main camera class is pylablib.devices.DCAM.
DCAMCamera.
34 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
These cameras require dcamapi.dll, which is installed with most of Hamamatsu software (such as HoKaWo or HiPic),
as well as with the freely available DCAM API, which also includes all the necessary drivers. Keep in mind, that you
also need to install the drivers for required corresponding camera type (USB, Ethernet, IEEE 1394). These drivers are
in the same installer, but need to be installed separately. You should also pay attention to the cameras supported by
the given DCAM driver version, since newer version do not support older cameras (e.g., ImageEM C9100 cameras are
only supported up to version 15). After installation, the DLL is automatically added to the System32 folder, where
pylablib looks for it by default. If the DLL is located elsewhere, the path can be specified using the library parameter
devices/dlls/dcamapi:
Connection
The cameras are identified by their index, starting from zero. To get the total number of cameras, you can run DCAM.
get_cameras_number():
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI and
exposure, starting and stopping acquisition, and operating the frame reading loop. The SDK also provides a universal
interface for getting and setting various camera attributes (called “properties” in the documentation) using their name.
You can use DCAMCamera.get_attribute_value() and DCAMCamera.set_attribute_value() for that, as well
as .cav attribute which gives a dictionary-like access:
0.1
To see all available attributes, you can call DCAMCamera.get_all_attributes() to get a dictionary with attribute
objects, and DCAMCamera.get_all_attribute_values() to get the dictionary of attribute values, with an option
of representing enum attributes either as text or as integer values. The attribute objects provide additional information:
attribute range, step, and units:
Additionally, there’s a couple of differences from the standard libraries worth highlighting:
• The library supports only symmetric binning, i.e., the binning factor is the same in both directions. For compat-
ibility DCAMCamera.get_roi() and DCAMCamera.set_roi() still return and accept both binning parameters
independently, but they are always the same when returned, and vbin is ignored when set.
• By default, the SDK does not provide independent control of the frame period and the exposure. Hence,
set_frame_period method is unavailable, and the frame rate is defined solely by the exposure.
Note: General camera communication concepts are described on the corresponding page
NI IMAQ is the interface from National Instruments, which is used in a variety of frame grabbers. It has been tested
with NI PCI-1430 and PCI-1433 frame grabbers together with PhotonFocus MV-D1024E camera.
The code is located in pylablib.devices.IMAQ , and the main camera class is pylablib.devices.IMAQ.
IMAQCamera.
Software requirements
This interfaces requires imaq.dll, which is installed with the freely available Vision Acquisition Software, which also
includes all the necessary drivers. After installation, the DLL is automatically added to the System32 folder, where
pylablib looks for it by default. If the DLL is located elsewhere, the path can be specified using the library parameter
devices/dlls/niimaq:
Connection
The cameras are identified by their name, which usually looks like "img0". To get the list of all cameras, you can use
NI MAX (Measurement and Automation Explorer), or IMAQ.list_cameras():
36 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
Unlike most camera classes, the frame grabber interface only deals with the frame transfer between the camera and the
PC over the CameraLink interface. Therefore, in can not directly control camera parameters such as exposure, frame
rate, triggering, ROI, etc. Some similar-looking parameters are still present, but they have a different meaning:
• External trigger controls frame transfer, not frame acquisition, which is defined by the camera. By default, when
the internal frame grabber trigger is used, the frame grabber transfer rate is synchronized to the camera, so every
frame gets transferred. However, if the external transfer trigger is used and it is out of sync with the camera, it
can result in duplicate or missing frames.
• ROI is defined within the transferred image, whose size itself is determined by the camera ROI. Hence, e.g., if
the camera chip is 1024x1024px and its roi is 512x512, then the frame grabber ROI can go only up to 512x512.
Any attempts to set it higher result in the frozen acquisition, as the frame grabber expects a larger frame than it
receives, and waits forever to get the rest.
The SDK also provides a universal interface for getting and setting various camera attributes using their name. You can
use IMAQCamera.get_grabber_attribute_value() and IMAQCamera.set_grabber_attribute_value() for
that:
At high frame rates (above ~10kFPS) dealing with each frame individually becomes too slow for Python. Hence, there
is an option to read out and process frames in larger ‘chunks’, which are 3D numpy arrays with the first axis enumerating
the frame index. This approach leverages the ability to store several frame buffers in the contiguous memory locations
(resulting in a single 3D array), and it essentially eliminates the overhead for dealing with multiple frames at high frame
rates, as long as the total data rate is manageable (typically below 600Mb/s).
This option can be accessed by calling using IMAQCamera.set_frame_format() method to set frames format to
"chunks" (former way of supplying fastbuff=True in IMAQCamera.read_multiple_images() is now depre-
cated). In this case, instead of a list of individual frames (which is the standard behavior), the method returns list of
chunks about 1Mb in size, which contain several consecutive frames.
The frame grabber needs some basic information about the camera: sensor size, bit depth, data transfer format, timeouts,
aux lines mapping, etc. In NI MAQ this information is contained in the so-called camera files. These files can be
assigned to cameras in the NI MAX, and are usually supplied by NI or by the camera manufacturer. In addition, NI
MAX allows one to adjust some settings within these files, which are read-only within the NI IMAQ software. These
include frame timeout and camera bit depth.
The communication with the camera itself greatly varies between different cameras. Some will have additional connec-
tion to control the parameters. Others use serial communication built into the CameraLink interface. This communi-
cation can be set up with IMAQCamera.setup_serial_params() and used via IMAQCamera.serial_read() and
IMAQCamera.serial_write(). The communication protocols are camera-dependent, and are frequently described
in the camera manual. However, some other cameras (e.g., Photon Focus) use proprietary communication protocol. In
this case, they provide their own DLLs, which independently use NI-provided DLLs for serial communication (most
notably, clallserial.dll) to communicate with the camera. In this case, one needs to maintain two independent
connections: one directly to the NI frame grabber to obtain the frame data, and one to the manufacturer library to
control the camera. This is the way it is implemented in PhotonFocus camera interface.
Known issues
• Sometimes when the acquisition is stopped and restarted without being cleared, the acquired frame counter does
not refresh. This might show up as the software not reporting any new frames. It has been tracked down to a
very low (~1ms) frame read timeout. Hence, it is recommended to keep this timeout at least at 500ms.
• If you are unable to access full camera sensor size, check the camera file (it can be opened in the text editor).
MaxImageSize parameter defines the maximal allowed image size, and it should be equal to the camera sensor
size.
• Same goes for bitness. If the camera bitness is higher than set up in the frame grabber, a single camera pixel gets
treated as several pixels by the frame grabber, typically resulting in 1px-wide vertical stripes on the image. In
the opposite case, the frame grabber expects more bytes than the camera sends, it never receives the full frame,
and the acquisition times out.
• Keep in mind that as long as the frame grabber is accessed in NI MAX, it is blocked from use in any other
software. Hence, you need to close NI MAX before running your code.
• As mentioned above, ROI is defined within a frame transferred by the camera. Hence, if it includes pixels with
positions outside of the transferred frame, the acquisition will time out. For example, suppose the camera sensor
is 1024x1024px, and the camera ROI is selected to be central 512x512 region. As far as the frame grabber is
concerned, now the camera sensor size is 512x512px. Hence, if you try to set the same frame grabber ROI (i.e.,
512x512 starting at 256,256), it will expect at least 768x768px frame. Since the frame is, actually, 512x512px,
the acquisition will time out. The correct solution is to set frame grabber ROI from 0 to 512px on both axes. In
general, it is a good idea to always follow this pattern: control ROI only on camera, and always set frame grabber
ROI to cover the whole transfer frame.
• Some frame grabbers have a limit on the data transfer rate (for one model observed to be about 200 Mb/s). If
the camera data generation rate exceeds it (e.g., it produces 1024x1024px 16-bit frames at >100FPS), then the
camera will raise IMG_ERR_FIFO error shortly after the acquisition start. In this case, you will need to reduce
the data rate by reducing the frame rate or frame size (through ROI, binning, or bitness).
Note: General camera communication concepts are described on the corresponding page
NI IMAQdx is the interface provided by National Instruments and which supports a wide variety of cameras. It is
completely separate from IMAQ, and it supports different communication interfaces: USB, Ethernet and FireWire. It
has been tested with Ethernet-connected PhotonFocus HD1-D1312 camera.
The code is located in pylablib.devices.IMAQdx, and the main camera class is pylablib.devices.IMAQdx.
IMAQdxCamera.
38 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
These cameras require imaqdx.dll, which is installed with the freely available Vision Acquisition Software. However,
the IMAQdx part of the software is proprietary, and requires purchase to use. If the software license is invalid, then
any attempt to communicate with cameras will result in License not activated error (although simply listing the
cameras still works). After installation, the DLL is automatically added to the System32 folder, where pylablib looks
for it by default. If the DLL is located elsewhere, the path can be specified using the library parameter devices/dlls/
niimaqdx:
Connection
The cameras are identified by their name, which usually looks like "cam0". To get the list of all cameras, you can use
NI MAX (Measurement and Automation Explorer), or IMAQdx.list_cameras():
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI, start-
ing and stopping acquisition, and operating the frame reading loop. The SDK also provides a universal interface for get-
ting and setting various camera attributes using their name. You can use IMAQdxCamera.get_attribute_value()
and IMAQdxCamera.set_attribute_value() for that, as well as .cav attribute which gives a dictionary-like access:
0
>> cam.set_attribute_value("Width", 512) # set the ROI width to 512px
>> cam.cav["Width"] # get the exposure; could also use cam.get_attribute_value("Width")
512
To see all available attributes, you can call IMAQdxCamera.get_all_attributes() to get a dictionary with attribute
objects, and IMAQdxCamera.get_all_attribute_values() to get the dictionary of attribute values. The attribute
objects provide additional information: attribute kind (integer, enum, string, etc.), range (either numerical range, or
selection of values for enum attributes), description string, etc.:
Since these properties vary a lot between different cameras, it is challenging to write a universal class covering a large
range of cameras. Hence, currently the universal class only has the basic camera parameter control such as ROI (without
binning) and acquisition status. For many specific cameras you might need to explore the attributes tree (either using
the Python class and, e.g., a console, or via NI MAX) and operate them directly in your code.
Known issues
• It seems like sometimes the camera communication settings might be interfering with its operation. It can show
up in an unexpected way, e.g., as an Attribute value is out of range error when starting acquisition. If
it looks like this might be the case, it is a good idea to open the camera in NI MAX (note that Ethernet cameras
are listed under Network Devices, not in the general device list) and try to snap a single frame. NI MAX might
report some problems with the settings and suggest resolution methods. Once the camera is operational, you can
close NI MAX and save the camera settings (request is shown upon closing).
• In general, Ethernet cameras work better with larger packet sizes. However, packets above 1500 bits (so-called
jumbo packets) are not supported by all network adapters by default. If this is the case, any attempt to acquire
images causes IMAQdxErrorTestPacketNotReceived error. One way to deal with that is to set the packet
size to 1500, which is done automatically when small_packet=True is supplied upon the camera creation.
The other is to enable jumbo packets in the adapter properties (in Windows this is done in Device Manager).
• Currently only the basic unpacked monochrome pixel formats are supported: Mono8, Mono10, Mono12, Mono16,
and Mono32. The reason is that even nominally well-defined types (e.g., Mono12Packed) have different formats
for different cameras. Currently any unsupported format will raise an error on readout by default. It it still
possible to read these out as raw frame data in the form of 1D or 2D numpy 'u1' array by enabling raw frame
readout using IMAQdxCamera.enable_raw_readout() method:
Note: General camera communication concepts are described on the corresponding page.
40 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Photon Focus CameraLink cameras transfer their data to the PC using frame grabbers (e.g., via NI IMAQ or Silicon
Software interfaces). Hence, the camera control is done through the serial port built into the CameraLink interface.
However, the cameras use a closed binary protocol, so all the control is done through the pfcam library provided by Pho-
ton Focus. It relies on the libraries exposed by the frame grabber manufacturers (e.g., the standard cl*serial.dll) to
communicate with the camera directly, meaning that the pfcam user simply calls its method, and all the communication
happens behind the scenes.
In principle, pfcam can work with any frame grabber. Because of that, there are two different kinds of classes for
this camera. To start with, there is .PhotonFocus.IPhotonFocusCamera, which provides interface for addressing
camera properties, but can not handle actual frame acquisition. Using this class directly leads to errors in any frame data
related methods (e.g., wait_for_frame, or read_multiple_images), and it is mostly intended to serve as a base
class to be combined with the actual frame grabber. Two such combined classes are already provided: .PhotonFocus.
PhotonFocusIMAQCamera for National Instruments frame grabbers using the NI IMAQ interface, .PhotonFocus.
PhotonFocusSiSoCamera for Silicon Software frame grabbers, and .PhotonFocus.PhotonFocusBitFlowCamera
for BitFlow frame grabbers. All classes are complete and ready to use. In addition to combining camera and frame
grabber control, they also implement basic consistency support, such as automatic adjustment of frame grabber ROI
and data transfer format.
Software requirements
These cameras require pfcam.dll, which is installed with freely available (upon registration) PFInstaller. In addition,
this DLL requires comdll.dll and the DLLs referring to a particular camera, e.g., mv_d1024e_160.dll. After
installation, the path to the DLLs (all located by default in Photonfocus/PFRemote/bin folder in Program Files)
is automatically added to system PATH variable, which is one of the places where pylablib looks for it by default. If the
DLLs are located elsewhere, the path can be specified using the library parameter devices/dlls/pfcam:
import pylablib as pll
pll.par["devices/dlls/pfcam"] = "path/to/dlls"
from pylablib.devices import PhotonFocus
cam = PhotonFocus.PhotonFocusIMAQCamera()
Connection
The camera class requires two pieces of information. First is the frame grabber interface connection, e.g., NI IMAQ
interface name (e.g., "img0") identified as described in the NI IMAQ documentation, or Silicon Software board and
applet described in Silicon Software documentation. The second piece of information is the pfcam port, which is either
a number starting from zero indexing the port in the ports list, or a tuple (manufacturer, port), e.g., ("National
Instruments", "port0"). To list all of the connected pfcam-compatible cameras, you can use the PFRemote soft-
ware (the interface number is given in parentheses after every connection option in the list) or run PhotonFocus.
list_cameras():
>> cam.close()
(continues on next page)
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI
and exposure, starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of
differences from the standard libraries worth highlighting:
• The SDK also provides a universal interface for getting and setting various camera attributes (called “properties”
in the documentation) using their name. You can use IPhotonFocusCamera.get_attribute_value() and
IPhotonFocusCamera.set_attribute_value() for that, as well as .cav attribute which gives a dictionary-
like access:
0.1
Some values (e.g., Window.Max or Reset) serve as commands; these can be invoked using
PhotonFocusIMAQCamera.call_command() method. To see all available attributes, you can call
IPhotonFocusCamera.get_all_attributes() to get a dictionary with attribute objects, and
IPhotonFocusCamera.get_all_attribute_values() to get the dictionary of attribute values. The
attribute objects provide additional information: attribute range, step, and units:
42 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Note: General camera communication concepts are described on the corresponding page
SC2 is the interface used with PCO cameras. It has been tested with pco.edge cameras with CLHS and regular Cam-
eraLink interfaces, and with pco.pixelfly usb cameras. A detailed description of the interface is given in the manual.
The code is located in pylablib.devices.PCO, and the main camera class is pylablib.devices.PCO.
PCOSC2Camera.
Software requirements
These cameras require SC2_Cam.dll, which is installed with the freely available pco.camware and pco.sdk tools.
By default, the library searches for DLLs in Digital Camera Toolbox/Camware4 and PCO Digital Camera
Toolbox/pco.sdk/bin folder in Program Files folder (or Program files (x86), if 32-bit version of Python
is running), as well as in the folder containing the script. If the DLLs are located elsewhere, the path can be specified
using the library parameter devices/dlls/pco_sc2:
Connection
The cameras are identified by their index, starting from zero, and, possibly, by their interface. To get the total number
of connected cameras, you can run PCO.get_cameras_number:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI and
exposure, starting and stopping acquisition, and operating the frame reading loop. The class also provides read-access
to all of the relevant camera data using PCOSC2Camera.get_full_camera_data(). This method returns data in the
internal manufacturer format; to interpret it, you should consult the manual.
Known issues
• Some cameras support only ROIs which are symmetric with respect to vertical flip. In other words, if the camera
detector has vertical size of 2160px, the vertical ROI should always have the form (x0, 2160-x0). It is still
possible to set non-symmetric ROI, but it is achieved by the software clipping, while the camera still reads out
the smallest symmetric ROI contained the selected one. As a result, the readout time for the same ROI size
strongly depends on the ROI position. For example, while vertical ROI of (0, 8) has only 8 pixel rows, it is not
symmetric, and requires reading the whole frame; hence, it will be as slow as the full-frame acquisition. On the
other hand, ROI of (1076, 1084) is symmetric, so the camera does read out only 8 rows. This results in vastly
faster readout time. You can use PCOSC2Camera.requires_symmetric_roi() to check if the symmetric ROI
is required.
Note: General camera communication concepts are described on the corresponding page
Picam is the interface provided by Teledyne Princeton Instruments and which supports a set of their cameras. It has
been tested with PIXIS 400 camera.
The code is located in pylablib.devices.PrincetonInstruments, and the main camera class is pylablib.
devices.PrincetonInstruments.PicamCamera.
Software requirements
These cameras require picam.dll, which is installed with the freely available PICam software. By default, the library
searches for DLLs in Princeton Instruments/PICam/Runtime folder in Program Files folder (or Program
files (x86), if 32-bit version of Python is running), as well as in the folder containing the script. If the DLL is
located elsewhere, the path can be specified using the library parameter devices/dlls/picam:
Connection
The cameras are identified by their serial number, which can look like "2800000001". To get the list of all cameras,
you can use .PrincetonInstruments.list_cameras:
44 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI,
starting and stopping acquisition, and operating the frame reading loop. The SDK also provides a universal interface for
getting and setting various camera attributes using their name. You can use PicamCamera.get_attribute_value()
and PicamCamera.set_attribute_value() for that, as well as .cav attribute which gives a dictionary-like access:
10.0
To see all available attributes, you can call PicamCamera.get_all_attributes() to get a dictionary with attribute
objects, and PicamCamera.get_all_attribute_values() to get the dictionary of attribute values. The attribute
objects provide additional information: attribute kind (integer, enum, float, etc.), range (either numerical range, or
selection of values for enum attributes), default value, etc.:
Since these properties vary a lot between different cameras, it is challenging to write a universal class covering a
large range of cameras. Hence, currently the universal class only has the basic camera parameter control such as ROI
(without binning), exposure, and acquisition status. For many specific cameras you might need to explore the attributes
tree using the Python class and operate them directly in your code.
Known issues
• Frame period obtained using PicamCamera.get_frame_period() can be an underestimate (i.e., it can over-
estimate the frame rate).
• While the cameras support multiple ROIs, only single-ROI readout is currently supported.
• Changing readout mode ("Readout Control Mode") to "Kinetics" might invalidate the current ROI, if it
was originally too large. Therefore, you would need to call set_roi again after setting this mode.
• In principle, the cameras support a variety of different metainfos which can be enabled or disabled separately.
However, for simplicity only two modes are supported in the camera class: either no metainfo, or full “standard”
metainfo (frame stamp, and start and stop timestamps). Any time the metainfo is enabled, disabled, or queried,
it is automatically “truncated” to one of these two modes.
Note: General camera communication concepts are described on the corresponding page
PVCAM is the interface provided by Teledyne Photometrics and which supports a set of their cameras. It has been
tested with Prime 95B camera.
The code is located in pylablib.devices.Photometrics, and the main camera class is pylablib.devices.
Photometrics.PvcamCamera.
Software requirements
These cameras require pvcam32.dll or pvcam64.dll, which is installed with the freely available (upon registration)
PVCAM software. By default, the library searches for DLL is automatically added to the System32 folder, where
pylablib looks for them by default. If the DLL is located elsewhere, the path can be specified using the library parameter
devices/dlls/pvcam:
Connection
The cameras are identified by their name, which can look like "PMUSBCam00". To get the list of all cameras, you can
use .Photometrics.list_cameras:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI,
starting and stopping acquisition, and operating the frame reading loop. The SDK also provides a universal interface for
getting and setting various camera attributes using their name. You can use PvcamCamera.get_attribute_value()
and PvcamCamera.set_attribute_value() for that, as well as .cav attribute which gives a dictionary-like access:
True
To see all available attributes, you can call PvcamCamera.get_all_attributes() to get a dictionary with attribute
objects, and PvcamCamera.get_all_attribute_values() to get the dictionary of attribute values. The attribute
46 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
objects provide additional information: attribute kind (integer, enum, float, etc.), range (either numerical range, or
selection of values for enum attributes), default value, etc.:
Since these properties vary a lot between different cameras, it is challenging to write a universal class covering a
large range of cameras. Hence, currently the universal class only has the basic camera parameter control such as ROI
(without binning), exposure, and acquisition status. For many specific cameras you might need to explore the attributes
tree using the Python class and operate them directly in your code.
At high frame rates (above ~10kFPS) dealing with each frame individually becomes too slow for Python. Hence, there
is an option to read out and process frames in larger ‘chunks’, which are 3D numpy arrays with the first axis enumerating
the frame index. This approach leverages the ability to store several frame buffers in the contiguous memory locations
(resulting in a single 3D array), and it essentially eliminates the overhead for dealing with multiple frames at high frame
rates, as long as the total data rate is manageable (typically below 600Mb/s).
This option can be accessed by calling using PvcamCamera.set_frame_format() method to set frames format to
"chunks". In this case, instead of a list of individual frames (which is the standard behavior), the method returns list
of chunks, which contain several consecutive frames.
Known issues
• Frame period obtained using PvcamCamera.get_frame_period() can be an underestimate (i.e., it can over-
estimate the frame rate), especially for USB-connected devices.
• While the cameras support multiple ROIs, only single-ROI readout is currently supported.
• Exposure time, exposure mode, and ROI are configured using special methods separately from other camera
attributes. Therefore, their corresponding attributes are read-only.
• Not all horizontal and vertical binning combinations are supported. The allowed combinations can be queries
using PvcamCamera.get_supported_binning_modes(). If the combination is not supported, it is truncated
down to the smallest supported one.
Note: General camera communication concepts are described on the corresponding page
Silicon Software produces a range of frame grabbers, which can be used to control different cameras with a CameraLink
interface. It has been tested with microEnable IV AD4-CL frame grabber together with PhotonFocus MV-D1024E
camera.
The code is located in pylablib.devices.SiliconSoftware, and the main camera class is pylablib.devices.
SiliconSoftware.SiliconSoftwareCamera.
Software requirements
This interfaces requires fglib5.dll, which is installed with the freely available (upon registration) Silicon Soft-
ware Runtime Environment (the newest version for 64-bit Windows is 5.7.0), which also includes all the necessary
drivers. After installation, the path to the DLL (located by default in SiliconSoftware/Runtime5.7.0/bin folder
in Program Files) is automatically added to system PATH variable, which is one of the places where pylablib looks
for it by default. If the DLL is located elsewhere, the path can be specified using the library parameter devices/dlls/
sisofgrab:
Connection
Figuring out the connection parameters is a multi-stage process. First, one must identify one of several boards. The
boards can be identified using SiliconSoftware.list_boards function. Second, one must select an applet. These
provide different board readout modes and, for Advanced Applets, various post-processing capabilities. These ap-
plets can be identified using SiliconSoftware.list_applets method, or directly from the Silicon Software RT
microDisplay software supplied with the runtime. The choice depends on the color mode (color vs. gray-scale and
different bitness), readout mode (area or line), and camera connection (single, double, or quad). Finally, depending on
the board and the camera connection, one of several ports must be selected. For example, if the frame grabber has two
connectors, but the camera only uses a single interface, then the double camera applet (e.g., DualAreaGray16) must
be selected, and the port should specify the board connector (0 for A, 1 for B):
>> cam.close()
Note that currently the code is organized in such a way, that only one port on a single board can be in use at one time.
48 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
Unlike most camera classes, the frame grabber interface only deals with the frame transfer between the camera and the
PC over the CameraLink interface. Therefore, in can not directly control camera parameters such as exposure, frame
rate, triggering, ROI, etc. Some similar-looking parameters are still present, but they have a different meaning:
• External trigger controls frame transfer, not frame acquisition, which is defined by the camera. By default, when
the internal frame grabber trigger is used, the frame grabber transfer rate is synchronized to the camera, so every
frame gets transferred. However, if the external transfer trigger is used and it is out of sync with the camera, it
can result in duplicate or missing frames.
• ROI is defined within the transferred image, whose size itself is determined by the camera ROI. Hence, e.g., if
the camera chip is 1024x1024px and its roi is 512x512, then the frame grabber ROI can go only up to 512x512.
Any attempts to set it higher result in frame being misshapen or having random data outside of the image area.
The SDK also provides a universal interface for getting and setting various attributes using their name.
You can use SiliconSoftwareCamera.get_grabber_attribute_value() and SiliconSoftwareCamera.
set_grabber_attribute_value() for that, as well as .gav attribute which gives a dictionary-like access:
512
The parameter can also be inspected in the Silicon Software RT microDisplay software.
At high frame rates (above ~10kFPS) dealing with each frame individually becomes too slow for Python. Hence, there
is an option to read out and process frames in larger ‘chunks’, which are 3D numpy arrays with the first axis enumerating
the frame index. This approach leverages the ability to store several frame buffers in the contiguous memory locations
(resulting in a single 3D array), and it essentially eliminates the overhead for dealing with multiple frames at high frame
rates, as long as the total data rate is manageable (typically below 600Mb/s).
This option can be accessed by calling using SiliconSoftwareCamera.set_frame_format() method to
set frames format to "chunks" (former way of supplying fastbuff=True in SiliconSoftwareCamera.
read_multiple_images() is now deprecated). In this case, instead of a list of individual frames (which is the
standard behavior), the method returns list of chunks about 1Mb in size, which contain several consecutive frames.
The frame grabber needs some basic information about the camera: sensor size, bit depth, data transfer format, timeouts,
aux lines mapping. This information can be specified using the grabber attributes. The most important transfer parame-
ters are the number of taps and the bitness of the transferred data, which can be set up using SiliconSoftwareCamera.
setup_camlink_pixel_format(). The values for this parameters can usually be obtained from the camera manuals.
Known issues
• The maximal frame rate is limited for some boards (at least for the tested microEnable IV AD4-CL board) by
about 20kFPS. It seems to be relatively independent of the frame size, i.e., it is not the data transfer rate issue.
One possible way to get around it is to use line readout applet, e.g., DualLineGray16, and set the frame height to
be the integer multiple of the camera frame. This will combine several camera frames into a single frame-grabber
frame, effectively lowering the frame rate at avoiding the issue. However, this sometimes leads to incorrect frame
splitting: the top line of the “combined” frame does not coincide with the top line of the original camera frame,
so all frames are shifted cyclically by some number of rows. Hence, it might require some post-processing with
frames merging and re-splitting.
• As mentioned above, ROI is defined within a frame transferred by the camera. Therefore, if it includes pixels
with positions outside of the transferred frame, the acquisition will be faulty. For example, suppose the camera
sensor is 1024x1024px, and the camera ROI is selected to be central 512x512 region. As far as the frame grabber
is concerned, now the camera sensor size is 512x512px. Hence, if you try to set the same frame grabber ROI
(i.e., 512x512 starting at 256,256), it will expect 768x768px frame. Since the frame is, actually, 512x512px, the
returned frame will partially contain random data. The correct solution is to set frame grabber ROI from 0 to
512px on both axes. In general, it is a good idea to always follow this pattern: control ROI only on camera, and
always set frame grabber ROI to cover the whole transfer frame.
Note: General camera communication concepts are described on the corresponding page
This is the interface used in Thorlabs scientific sCMOS cameras such as Kiralux or Zelux. It has been tested with
Thorlabs Kiralux camera.
The code is located in pylablib.devices.Thorlabs, and the main camera class is pylablib.devices.
Thorlabs.ThorlabsTLCamera.
Software requirements
50 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Connection
The cameras are identified by their serial number. To list all of the connected cameras, you can run Thorlabs.
list_cameras_tlcam:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI and
exposure, starting and stopping acquisition, and operating the frame reading loop.
For color cameras, several readout modes are available, which can be set up using ThorlabsTLCamera.
set_color_format() method. By default, the color cameras output the frames in the linear RGB format (each frame
is a 3D array with the last axis encoding color channel).
Warning: The library appears to be not entirely stable: every time acquisition start is issued, there is small (0.1-
1%) chance that it will not actually start, which results in timeout errors. Furthermore, there are occasional crashes
on the SDK unloading (i.e., camera closing), especially when acquisition has been started and stopped multiple
times. It is unclear, what is the cause of this behavior, but it seems to originate from the manufacturer’s DLL (bare-
bones example and the native Python library reproduce this behavior). Hence, it might be different with different
DLL versions.
Note: The DLL prints some debug information in the console when camera list is requested and when the camera is
opened. At the moment, it is unclear how to get rid of it.
Note: General camera communication concepts are described on the corresponding page
This is the interface used in multiple cameras, including many simple Thorlabs and IDS cameras. It has been tested
with IDS SC2592R12M and Thorlabs DCC1545M.
Essentially identical interface is available under two different implementations: either as Thorlabs uc480 or as IDS
uEye. Both of these seem to cover exactly the same cameras, both are freely available from the manufacturers, and
both implement exactly the same functionality. However, these interfaces are not interchangeable, and each camera will
only interact with one of them depending on which driver it happens to use (usually based on which of the software
packages was installed last). Hence, if you have both ThorCam and IDS Software Suite installed, you would need
to check both interfaces. Normally, the interface should correspond to the software which can connect to the camera
(either ThorCam or uEye Cockpit).
The code is located in pylablib.devices.uc480, and the main camera class is pylablib.devices.uc480.
UC480Camera. Note that while the names only refer to uc480, the same functions and classes equally cover IDS
uEye interface if the appropriate backend argument is provided.
Software requirements
Depending on the interface, these cameras require either uc480.dll, or ueye_api.dll. These are automatically
installed with, correspondingly, the freely available ThorCam software or with IDS Software Suite (upon registration;
note that you need specifically IDS Software Suite, and not IDS peak). By default, the library searches for DLLs in the
corresponding Program Files folder (Thorlabs/Scientific Imaging/ThorCam or IDS/uEye), in the locations
placed in PATH during the installation, as well as in the folder containing the script. If the DLLs are located elsewhere,
the path can be specified using the library parameter devices/dlls/uc480 or devices/dlls/ueye:
Connection
The cameras are identified by their camera ID or device ID (both starting from 1). Device ID corresponds to the connec-
tion order of the cameras: it is guaranteed to be unique, but will change if the camera is disconnected and reconnected
again. On the other hand, camera ID is tied to the camera, but it is set to 1 by default for all cameras, and needs to be
manually assigned using UC480Camera.set_camera_id(). Alternatively, one can use other characteristics (model
or serial number) as a unique identifier. To list all of the connected cameras together with their basic information, you
can run uc480.list_cameras():
52 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
If cam_id = 0 is provided (default), the software connects to the first available camera.
By default, the code above uses Thorlabs uc480 interface. If you want to use ueye interface, you need to specify
backend="ueye" argument to the corresponding functions and to the camera class upon creation. With that, the
example above becomes:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI
and exposure, starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of
differences from the standard libraries worth highlighting:
• Some cameras support both binning (adding several pixels together) and subsampling (skipping some
pixels). However, only one can be enabled at a time. They can be set independently us-
ing, correspondingly, UC480Camera.get_binning()/UC480Camera.set_binning() and UC480Camera.
get_subsampling()/UC480Camera.set_subsampling(). They can also be set as binning factors in
UC480Camera.get_roi()/UC480Camera.set_roi(). Whether binning or subsampling is set there can be
determined by the roi_binning_mode parameter supplied on creation.
• Uc480 API supports many different pixel modes, including packed ones. However, pylablib currently supports
only monochrome unpacked modes.
• Occasionally (especially at high frame rates) frames get skipped during transfer, before they are placed into the
frame buffer by the camera driver. This can happen in two different ways. First, the frame is simply dropped with-
out any indication. This typically can not be detected without using the framestamp contained in the frame info, as
the frames flow appear to be uninterrupted. In the second way, the acquisition appears to get “restarted” (the inter-
nal number of acquired frames is dropped to zero), which is detected by the library. In this case there are several
different ways the software can react, which are controlled using UC480Camera.set_frameskip_behavior().
The default way to address this “restart” event ("ignore") is to ignore it and only adjust the internal acquired
frame counter; this manifests as quietly dropped frames, exactly the same as the first kind of event. In the other
method ("skip"), some number of frames are marked as skipped, so that the difference between the number of
acquired frames and the internal framestamp is kept constant. This makes the gap explicit in the camera frame
counters. Finally ("error"), the software can raise uc480FrameTransferError when such event is detected,
which can be used to, e.g., restart the acquisition.
One needs to keep in mind, that while the last two methods make “restarts” more explicit, they do not address the
first kind of events (quiet drops). The most direct way to deal with them is to use frame information by setting
return_info=True in frame reading methods like read_multiple_images. This information contains the
internal camera framestamp, which lets one detect any skipped frames.
Note: General camera communication concepts are described on the corresponding page
Mightex manufactures a set of USB2 and USB3-interfaced cameras with several somewhat different APIs. Currently
only S-series cameras are implemented and tested.
The code is located in pylablib.devices.Mightex, and the main camera class is pylablib.devices.Mightex.
MightexSSeriesCamera.
Software requirements
These cameras require MT_USBCamera_SDK_DS.dll and accompanying MtUsbLib.dll, which can be obtained in the
freely available S-series camera software package (the current latest version is from 2019.01.04). This software does
not require installation, and the required DLLs are contained in the DirectShow/MightexClassicCameraEngine
folder withing the archive (do not confuse them with the regular MT_USBCamera_SDK.dll library, which is similar,
but has some downsides regarding threading). Since these DLLs are not registered anywhere OS-wide, you should
either specify them using the library parameter devices/dlls/mightex_sseries (both the containing folder path
and the direct file path work), or copy the two DLL files to the folder containing your script:
Connection
The cameras are identified by their index among the present cameras (starting from 1). To get the list of all cameras,
you can use Mightex.list_cameras_s:
Operation
The operation of these cameras is relatively standard. They support all the standard methods for dealing with ROI,
starting and stopping acquisition, and operating the frame reading loop. However, there’s a couple of differences from
the standard libraries worth highlighting:
• The multi-camera support from the SDK is fairly poor, e.g., only a single OS process can communicate with
cameras (even if different processes try to access different cameras), and several cameras are always polled in
sequence, meaning that the slowest camera determines the overall frame rate. Therefore, only the single camera
operation is supported, although one can still select specific camera if several are connected to the same PC.
54 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
• In some cases ROIs with extreme aspect ratios (e.g., 32x1024 px) can freeze the camera, such that it only start
operating again after the software restart. Therefore, there should be generally be avoided.
• Colored cameras are in principle supported, but the returned image is not debayered, meaning that it is still a
monochrome image with different pixels within 2x2 sub-squares corresponding to different colors.
2.2.3 Stages
Note: General device communication concepts are described on the corresponding page.
Basic example
Almost all stages implement the same basic functionality for moving, stopping, homing, and querying the status:
Some stages will miss some of this functions (e.g., no homing), but if it’s present, it works roughly in the same manner.
Some concepts are explained below in more detail.
Basic concepts
Stages have two basic strategies for keeping track of the position. The first one is counting the steps. The problem with
it is that once the device is powered up, its position in unknown. Hence, it requires some kind of homing procedure,
which usually involves moving to a predefined position and zeroing out the step counter there. This position is defined
by the hardware, usually in the form of a limit switch: a physical switch located at the end of the stage travel range,
which changes the state when the stage reaches its position. It also usually automatically turns off the motion when
tripped, to prevent the motor from overheating or the stage from breaking.
When stepper motors are used, the size of each step (or microstep, if used) is a reasonably well-defined fraction of a turn,
so counting them gives fairly reproducible results. On the other hand, piezo slip-stick sliders (such as Attocube, Smar-
Act, or Picomotor) have inherently unreliable steps size which depends on, e.g., load, direction, position, temperature,
or other environmental factors. In this case steps counting, while possible, usually leads to long-term drifts.
If the reliable counting is impossible, like in the case of sliders or regular DC (as opposed to stepper) motors, the
manufacturer might add a hardware position readout. It can be digital (encoder) or analog (e.g., resistive, capacitive,
or optical readout). The first kind is generally simpler, cheaper and more reliable, but the second one can provide
much higher resolution, and can work in more extreme environments (high vacuum, cryogenics). In both cases, the
controllers would typically have some kind of feedback loop to smoothly control the motion speed and direction to
approach a given position.
Almost all stages allow control or readout of position in motor steps, encoder steps, or some other internal units. It is
usually not straightforward, or sometimes even impossible, to convert those to real units. In cases where it is possible,
it is defined by the motor gearbox and the screw pitch (for linear stages); in most cases, this ratio is provided in the
motor or translation stage manual (which can be different from the motor controller manual, and the two might even be
completely independent). Sometimes, one even has to do explicit calculations, e.g., getting the number of microsteps
per revolution from the controller and motor manufacturer, and the displacement per step from the stage manufacturer.
Speed control
In many cases, the motor speed is ramped up and down linearly rather than abruptly; hence, both the “cruising” speed
and the ramping acceleration can, in principle, be configured. Usually they are defined in, respectively, steps/s and
steps/s^2, although sometimes internal units have to be used.
56 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Here we talk more practically about using pylablib to perform common tasks.
Motion
The most standard motion methods are move_to, which moves to a specified position, move_by, which moves by a
specified distance or number of steps, and jog, which moves continuously in a given direction until stopped or run into
a limit switch. If both move_to and move_by are present, they usually perform the same operation under the hood:
stage.move_by(s) and stage.move_to(stage.get_position()+s) yield the same result.
In almost all cases these commands are asynchronous, in the sense that they simply initialize the motion and continue
immediately:
>> stage.move_by(1000)
>> stage.is_moving() # the stage is moving, but the execution continues
True
>> time.sleep(1.)
>> stage.is_moving() # after 1s the motion is done
False
To stop immediately (which is usually only used with jog commands) you can use the stop method. In some cases,
there are two different stop kinds: “soft” with a ramp-down, or “hard” which immediately ceases motion.
Since the motion commands are asynchronous, the devices provide two methods to synchronize it with the script
execution. The first one, is_moving, checks if the stage is currently in motion. The second one, wait_move, pauses
the execution until the stage motion is finished.
In addition, many stages provide methods to obtain additional information, e.g., get_status (which, usually, returns
state of motion, limit switches, possible errors, etc.), or get_current_speed.
Position readout
If a stage has position readout (either hardware sensor, or step counting), it is implemented with the get_position
method. In most cases, it will be accompanied with the set_position_reference method, which lets one change
the currently stored position, effectively adding an offset to all further position readings:
>> stage.get_position()
10000
>> stage.set_position_reference(20000) # change current reference to
>> stage.get_position() # note that it reacts immediately, unlike move_to; no physical␣
˓→motion happened
20000
>> stage.move_to(21000) # move by 1000 steps; equivalent to .move_by(1000), or .move_
˓→to(11000) before the reference change
Note that it only changes the internal counter state, and does not cause any stage motion (which is performed by
move_to).
Axis selection
Many controllers support simultaneous control of several different motors. In this case, all of their methods take an
additional axis (in most cases) or channel argument, which specify the exact motor. In cases where usually only one
motor is controlled (e.g., TMCM1110 or Thorlabs KDC101), this parameters is set to the default value, and is closer
to the end of the parameter list. If having multiple controlled stages is the default (e.g., Attocube ANC350 or Arcus
Performax), this parameter is usually the first one, and it has to be specified. In this cases, the methods frequently allow
to set this parameter to "all", which means that the action is performed for all axes, or the results is returned for all
axes (usually in a form of a list or a dictionary).
The channels are usually specified by their index starting from 0 or 1, although some stages adopt a different labeling
(e.g., Arcus Performax labels them as X, Y, Z, and U). The exact specification is given in the specific class description.
Homing
As mentioned above, often stages require homing to get absolute position readings. It needs to be done every time the
stage is power-cycled, but the homing parameters usually persist between different re-connections.
If homing is implemented, it is done using the home method. In addition, there can also be an is_homed method,
which checks if the homing has already been performed. If the method is present, then by default home will not execute
if is_homed returns True, unless forced.
Some stages do not have an explicit homing method, but can be manually homed by, e.g., running the stage to the limit
switch and setting the position reference to 0.
Note: General stage communication concepts are described on the corresponding page
Attocube positioners
Attocube has two main positioner controllers: ANC300 and ANC350. These cover different but somewhat overlapping
positioner classes, and have fairly different programming interfaces.
Attocube ANC300
This controller is aimed at open-loop (i.e., no position readout) positioners. It is a chassis with a single PC communi-
cation module and up to 7 individual piezo control modules: ANM150 (only stepping), ANM200 (only scanning), or
ANM250 (stepping and scanning).
The device class is pylablib.devices.Attocube.ANC300.
Software requirements
The controller has several communication modes: USB, RS232, and Ethernet. USB mode requires a driver supplied
with the controller (or downloaded from the controller itself using its Ethernet connection and HTTP port), which
makes ANC300 appear as a virtual COM port. RS232 requires a USB-to-RS232 adapter, which usually manifests in
the same way. Finally, Ethernet connection works like any other networks device. The controller has been tested with
USB and Ethernet communication modes (RS232 is identical to USB, so it should operate as well).
Of all of these modes only USB requires specialized drivers, and the other two are usually available purely through the
built-in OS capabilities.
58 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Connection
The device is identified by its communication address. It can be either a serial port (e.g., "COM5"), or an IP address (e.g.,
"192.168.1.100"); see connection description for more information. The backend is chosen automatically based on
the connection parameter. Additionally, Ethernet connection requires a password; by default, the standard Attocube
password "123456" is used, but if you specified a custom password, you need to provide it upon connection:
>> atc1.close()
>> atc2.close()
Note that since Ethernet inherently supports multiple connections, it is possible to control the same devices in multiple
scripts at the same time.
Operation
This controller has several features and differences compared to most other stages and sliders:
• The controller is inherently multi-axis, hence it always take the axis as the first argument. The axes are numbered
starting from 1, and are addressed according to the chassis spaces, so some can be skipped or missing. To update
the list of connected axes, use ANC300.update_available_axes() (called automatically on connection).
• Different control modules provide different functionality. Hence, not all methods would work for all axes: offset
voltage commands such as ANC300.set_offset() do not work with ANM150 module, while stepping com-
mands such as ANC300.move_by() do not work with ANM200 module. To get the module kinds and serial
numbers, use ANC300.get_axis_serial().
• The most important stepping parameters are step voltage amplitude and step frequency (number of steps per
second). These can be controlled with, correspondingly, ANC300.get_voltage()/ANC300.set_voltage()
and ANC300.get_frequency()/ANC300.set_frequency().
• Different axes can be enabled and disabled (i.e., connected or grounded) using ANC300.enable_axis() and
ANC300.disable_axis(). Disabling an axis completely shuts off the connection to the positioner, which usu-
ally reduces the noise. In addition, there can be different operation modes for only offset, only stepping, or
combination of the two.
• It is possible to measure the positioner capacitance using ANC300.get_capacitance(), which is useful in
identifying breaks or shorts in the wiring or faults in the piezos. By default, this method simply returns the last
measured value. To re-measure, call it with measure=True. Note that after the measurement is done, the axis
is automatically disabled, and needs to be enabled explicitly:
200E-9
>> atc.is_enabled(1)
False
Note that this is also the only way to know if there is an actual positioner connected to the given control module.
Attocube ANC350
This controller is aimed at closed-loop (i.e., with position readout) positioners. It can control up to 3 positioners.
The device class is pylablib.devices.Attocube.ANC350.
Software requirements
The controller has USB and Ethernet modes. USB mode requires a driver supplied with the controller. The commu-
nication is done via PyUSB, which means that it does not require any additional Attocube DLLs, although you might
need to install libusb (see PyUSB for more details). Ethernet control is supplied as an additional purchasable option
and can be configured using the supplied Daisy control software.
This device has only been tested with a USB connection.
Connection
When using a USB connection, the device is identified by its index among all the connected ANC350 devices. To get
the total number of devices, you can use Attocube.get_usb_devices_number_ANC350:
Ethernet connection should work in the same manner as any other similar devices, i.e., the address and, possibly, the
port should be provided.
Operation
This controller has several features and differences compared to most other stages and sliders:
• The controller is inherently multi-axis, hence it always take the axis as the first argument. The axes are numbered
0 through 2. You can check if the slide is connected to the given axis using ANC350.is_connected().
• Different axes can be enabled and disabled (i.e., connected or grounded) using ANC300.enable_axis() and
ANC300.disable_axis(). Disabling an axis completely shuts off the connection to the positioner, which usu-
ally reduces the noise.
• It is also possible to control the sensor voltage using ANC350.get_sensor_voltage()/ANC350.
set_sensor_voltage() methods. Reducing this voltage lowers the heating produced by the sensor, which
becomes especially important at very low (<1K) temperatures.
• The most important stepping parameters are step voltage amplitude and step frequency (number of steps per
second). These can be controlled with, correspondingly, ANC350.get_voltage()/ANC350.set_voltage()
and ANC350.get_frequency()/ANC350.set_frequency().
• It is possible to measure the positioner capacitance using ANC350.get_capacitance(), which is useful in
identifying breaks or shorts in the wiring. By default, this method simply returns the last measured value. To
re-measure, call it with measure=True.
60 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
• Fine positioning is performed using the position readout and the feedback loop. Then a move_to/move_by
command is issued, this feedback loop is activated, and the positioner tries to reach and stay at the cur-
rent position. You can use ANC350.is_target_reached() to check if the target is reached, ANC350.
get_target_position() to get the target, and ANC350.get_precision()/ANC350.set_precision() to
control the target precision.
• In addition, there is a method ANC350.move_by_steps(), which mimics ANC300.move_by() by moving for
a given number of steps instead of a given distance. However, due to implementation limitations, this method is
synchronous, i.e., it waits until all steps are performed. Nevertheless, ANC350.jog() is still asynchronous.
Note: General stage communication concepts are described on the corresponding page
Thorlabs has a variety of APT/Kinesis devices for various motion-related functionality (mostly motor controllers and
piezo drivers), which share the same API. The library uses an older and more low-level APT protocol to communicate
with these devices. So far it has been only implemented for motor controllers and some specialized devices and tested
with KDC101, KST101, K10CR1, and BSC201 motor controllers, KIM101 piezo motor controller, KPZ101 piezo
output controller, and TPA101 quadrature sensor controller.
The main device classes are pylablib.devices.Thorlabs.BasicKinesisDevice for a generic Kinesis/APT de-
vices pylablib.devices.Thorlabs.KinesisMotor aimed at motor controllers such as K10CR1 or KDC101,
pylablib.devices.Thorlabs.KinesisPiezoMotor for piezo drivers such as KIM and TIM, and pylablib.
devices.Thorlabs.KinesisPiezoController for piezo controllers such as KPZ and TPZ.
Software requirements
The connection is done using Thorlabs APT protocol, so it needs the corresponding APT drivers. Pylablib communi-
cates directly with the FTDI USB-to-RS232 using pyft232 chip inside the controller, so it bypasses most of the Thorlabs
software. This means that it does not need any Thorlabs-supplied DLLs, but it also means that it can not work with the
simulated devices, since these are simulated on a level above the direct serial communication.
In some cases pyft232 library can not find the required ftd2xx.dll library, which leads to an error. There are several
ways to get around this. First, you can install the FTDI drivers from the manufacturer’s website. Setup executable for
Windows automatically places the necessary DLL into the System32 folder, where pyft232 can discover them. Alter-
natively, you can copy the DLLs there yourself from the Thorlabs APT installation. Their default location is Program
Files\Thorlabs\APT\Drivers\APT\USB Driver\amd64 for 64-bit version or Program Files\Thorlabs\APT\
Drivers\APT\USB Driver\i386 for 32-bit version. Note that in the first case the file is called ftd2xx64.dll, and
you will need to rename it to ftd2xx.dll when copying to the System32 folder.
Connection
On Windows devices are identified by their address, which correspond to their serial numbers. To get the list of all the
connected devices, you can use Thorlabs.list_kinesis_devices:
On Linux they directly appear as virtual serial ports, e.g., /dev/ttyUSB0. Hence, there you need to identify which
device file corresponds your device (e.g., by unplugging and plugging it back in to see which device shows up). After
that, you can use this name as the device address:
Note that on Linux Thorlabs.list_kinesis_devices will not produce a correct list, since it uses a different API.
In the worst case, it can crash the process.
Operation
Standard motors
This controller has several features and differences compared to most other stages and sliders:
• There are two different classes of devices which require slightly different communication approach: generic
USB devices and rack-bay devices. These are hard to detect a priori, so by default generic USB de-
vice (which covers the majority of equipment) is assumed. If this assumption is incorrect, the com-
munication becomes impossible, and an attempt to connect to the device raises a communication er-
ror ThorlabsBackendError: backend exception: 'read returned less data than expected'
('read returned less data than expected'). If you experience this error, you should first power-cycle
the device, as it often gets stuck in a non-communicable state, and then double-check that the standard Thorlabs
software (Kinesis or APT) can detect and control it. If this is the case, you should supply is_rack_system=True
to the controller:
• There are several different ways to specify the stage calibration, which are controlled by the scale parameter
supplied upon the connection. By default (scale = "step"), it accepts and returns position in motor steps,
velocity in steps/s and acceleration in steps/s^2 (scaling coefficients for the latter two are determined from the
controller model). If scale = "stage", the class attempts to autodetect the stage and use meters or degrees
instead of steps; in addition you can supply the stage name (e.g., "MTS25-Z8") as a scale instead of relying on the
autodetection. If there is no calibration for the stage that you have, you can instead supply a single scaling factor,
which specifies the number of steps per physical unit (e.g., for "MTS25-Z8" stage and mm units, one would supply
scale = 34304). The stage scaling can be obtained from the APT manual. Finally, one can supply a 3-tuple of
scales for position, velocity and acceleration (all relative to the internal units). The details are given in the APT
manual. To ensure that the units have been applied and/or autodetected correctly, you can use KinesisMotor.
get_scale(), KinesisMotor.get_scale_units() and KinesisMotor.get_stage() methods.
• By default, the controllers are treated as single-axis. If several axes are supported, they can be specified using
channel argument in the corresponding methods such as move_to or get_status. In addition, you can specify
the number of channels using KinesisMotor.set_supported_channels() method, in which case settings
channel="all" in the method would act on all the channels.
• The motor power-up parameters for homing, jogging, limit switches, etc., can be different from the pa-
rameters showing up in the APT/Kinesis controller. This can lead to problems if, e.g., homing speed is
too low, so the motor appears stationary while homing. You should make sure to check those parame-
ters using KinesisMotor.get_velocity_parameters(), KinesisMotor.get_jog_parameters(),
KinesisMotor.get_homing_parameters(), KinesisMotor.get_gen_move_parameters(), and
KinesisMotor.get_limit_switch_parameters().
62 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Piezo motors
This controller has several features and differences compared to most other stages and sliders:
• The controllers are treated as multi-axis. However, to be compatible with other Kinesis motor, the channel
argument is not required, and it defaults to the currently selected “default” channel (1 in the beginning). To control
different channels, you can either supply channel argument explicitly, or specify a different default channel using
KinesisPiezoMotor.set_default_channel() or KinesisPiezoMotor.using_channel().
• The motor power-up parameters for jogging and drive can be different from the parameters showing up in
the APT/Kinesis controller. This can lead to problems if, e.g., speed is too low. You should make sure to
check those parameters using KinesisPiezoMotor.get_drive_parameters() and KinesisPiezoMotor.
get_jog_parameters().
• Even open-loop controllers support absolute positioning, which is achieved simply by counting steps in both
directions. However, unlike stepper motors or encoders, these steps can be different depending on the direction,
position, instantaneous load, speed, etc. Hence, the absolute positions quickly become unreliable. It is, therefore,
recommended to generally use relative positioning using KinesisPiezoMotor.move_by() method.
Piezo controllers
This controller acts more as a voltage amplifier than as a stage. Therefore, it does not have any motion-related com-
mands (such as move_to), and instead is mainly operated through KinesisPiezoController.enable_channel()
and KinesisPiezoController.set_output_voltage() methods to control the output. In addition, it sup-
ports controlling the full output range (KinesisPiezoController.set_voltage_range()) and the voltage source
(KinesisPiezoController.set_voltage_source()).
Quadrature detector
These are fairly different from the other discussed devices, since they are more related to sensors than to motors. This
controller takes signal from a quadrature photodetector and implements a PI control loop to feed back to some control
device (e.g., a piezo driver or a galvo mirror). Hence, all of its methods are fairly distinct from the usual motors. Nev-
ertheless, it is described here, since it still belongs to the APT/Kinesis family of devices and shares their detection and
connection approach. The device is implemented in the pylablib.devices.Thorlabs.KinesisQuadDetector
class.
The operation is fairly straightforward: it implements control of PID parameters, output parameters (such as limits),
operation mode (open/close loop), allows for reading current state and setting outputs in the open-loop mode.
Note: General stage communication concepts are described on the corresponding page
Thorlabs has a line of basic resonant piezoelectric motor stages from Elliptec, which include several rotational and linear
stages and feature step-motion and position readout. The library has been tested with ELL18 and ELL14 rotational
mounts.
The main device class is pylablib.devices.Thorlabs.ElliptecMotor.
Software requirements
The connection is done using a USB connection together with a built-in USB-to-RS232 chip. It is automatically
recognized as a serial port, and no additional software is required. In case the device is not recognized as a serial port,
you can fix it by installing freely available Thorlabs Elliptec software.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
These devices have several features and differences compared to most other stages and sliders:
• There is a possibility to have several (up to 16) devices connected to the same controller board (i.e., the same serial
port address) using bus distributor. However, since they all use the same serial port, they are all controlled from
a single ElliptecMotor instance. Hence, in order to refer to specific devices, each communication requires an
address (integer from 0 to 15), which is specified by addr argument available in almost all methods. When this
argument is None (which is the default value), the so-called default address is used, which can be accessed via
ElliptecMotor.get_default_addr() and ElliptecMotor.set_default_addr() methods. By default,
all connected devices are discovered up the connection, and the first available devices is used as default; therefore,
if only a single devices is connected, addr argument does not have to be used.
• Compared to most motor controllers, Elliptec devices have some limitation related to their inability to com-
municate while the motor is moving. Therefore, there are no methods to query whether the motor is moving,
or stop the motion once initiated. To address that and to simplify the library and the user code, all motion-
related methods (ElliptecMotor.move_to(), ElliptecMotor.move_by(), and ElliptecMotor.home())
are made synchronous, i.e., the execution is paused until the motion is complete. Note that this is true even when
several devices are connected to the same port.
• There are several different ways to specify the stage calibration, which are controlled by the scale parameter
supplied upon the connection. By default (scale = "stage"), the internal device calibration is used, so all
of the positions are expressed in device-specific units (deg or mm). If scale = "step", all of the position
are specified in internal device steps instead. Finally, if scale is a number, it is the proportionality coefficient
between the position units and the internal steps, i.e., the position in user-defined units is multiplied by it to
specify the position in steps. The scale for individually addressed devices can be set using ElliptecMotor.
get_scale() and ElliptecMotor.set_scale() methods.
Note: General stage communication concepts are described on the corresponding page
64 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Newport Picomotor is a series of actuators, usually in a screw format, based on the slip-stick piezo actuation mecha-
nism (similar to, e.g., Attocubes). Operating them requires a driver/controller to output specific voltage pulses. The
basic modern open-loop controller is Newport 8742, which can drive up to 4 actuators (but only one at a time), sup-
ports connection via USB or Ethernet, and can be daisy-chained to communicate with several controllers through one
connection. The class has been tested with this controller and a single standard actuator.
The device class is pylablib.devices.Newport.Picomotor8742.
Software requirements
The controller has two communication modes: USB, and Ethernet. USB mode requires a driver supplied with the
freely available PicomotorApp software, while Ethernet connection works like any other networks device and does not
require any additional software. The controller has been tested both with USB and Ethernet communication modes.
Connection
When using the USB connection, the device is identified by its index, starting from 0. To get the number of connected
devices, you can use Newport.get_usb_devices_number_picomotor:
Ethernet connection requires a host name or an IP address. Both can be set up by first connecting the device via USB
or by using the PicomotorApp software (in the Setup -> Ethernet menu). After that, they can be supplied to the
class instead of index:
>> stage1.close()
Operation
This controller has several features and differences compared to most other stages and sliders:
• The controller is inherently multi-axis, hence it always take the axis as the first argument. The axes are labeled
numerically starting from 1 (i.e., 1, 2, 3, and 4). The list of all axes is related to the exact controller, an can be
obtained using Picomotor8742.get_all_axes().
• There is an option to auto-detect motors and their kind using Picomotor8742.autodetect_motors() method.
However, since it involves stepping the motor, it usually makes more sense to detect them once and then store
them into the non-volatile (i.e., power-independent) memory using Picomotor8742.save_parameters().
• Even open-loop controllers support absolute positioning, which is achieved simply by counting steps in both
directions. However, unlike stepper motors or encoders, these steps can be different depending on the direction,
position, instantaneous load, speed, etc. Hence, the absolute positions quickly become unreliable. It is, therefore,
recommended to generally use relative positioning using Picomotor8742.move_by() method.
• As mentioned above, the controller support daisy-chaining using RS-485 connections. It allows to connect sev-
eral controllers together while still only using a single PC connection. In this case, it is recommended to supply
multiaddr=True upon connecting to the device. If, in addition scan=True is set (default), then upon connec-
tion the controller scans for all other connected devices, resolves their address conflicts, and builds the list of the
available addresses (address is a number between 1 and 31). The list can later be read using Picomotor8742.
get_addr_map(), and the network rescanned using Picomotor8742.scan_devices(). To refer to a specific
device, its address should be specified using addr parameter of a method; by default it is set to None, which
selects the device connected to the PC.
Note: General stage communication concepts are described on the corresponding page
Arcus has several motor controllers and drivers, which are mainly different in their number of axes, communication
possibilities, and driving function. They are also distributed under different names, e.g., Nippon Pulse America (NPA)
or Newmark Systems. However, the models nomenclature is the same: there is 4EX for 4-axis controllers with USB and
RS485 connection, 2EX/2ED for 2-axis controllers with USB and RS485 connections, and 4ET for 4-axis controllers
with Ethernet connection. The class has been tested with 4EX and (partially) 2ED controllers with USB and RS-485
connectivity mode, but other controllers mentioned above should also work.
The main device classes are pylablib.devices.Arcus.Performax4EXStage or 4-axis controllers,
pylablib.devices.Arcus.Performax2EXStage for 2-axis controllers, and pylablib.devices.Arcus.
PerformaxDMXJSAStage for simple single-axis controller (DMX-J-SA). In addition to a different number of axes,
they have several syntax differences, so one can not substitute for the other.
In addition, there is also a generic Performax stage class pylablib.devices.Arcus.GenericPerformaxStage,
which implements only the most basic functions: ASCII communication with the device and basic methods such as
device name request. It can be used with new or not currently supported Arcus stages to directly control them using
the ASCII control language (usually described in the stage manual).
Software requirements
The controller has several communication modes: USB, RS485, and Ethernet. USB mode requires a driver supplied
with the operation software: Arcus Drivers and Tools, Performax Series Installer, and Performax USB Setup (all
obtained at Arcus website). Installing all three seem to be sufficient. Once the appropriate USB drivers are installed, one
can connect the device directly via its USB port and use the manufacturer DLLs PerformaxCom.dll and SiUSBXp.
dll to communicate with the device. They can be obtained on the manufacturer’s website and placed in the folder with
the script, or in the System32 Windows folder. If the DLL is located elsewhere, the path can be specified using the
library parameter devices/dlls/arcus_performax:
Warning: There appear to be some issues for USB-controlled devices with Python 3.6 which result in out-of-
bounds write, memory corruption, and undefined behavior. Hence, Python 3.7+ is required to work with this
device.
66 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
RS-485 connection does not require any device-specific drivers or DLLs, but it does need RS-485 controller connected
to the PC. Such controllers usually show up as virtual COM ports, and they typically do not need any additional drivers.
Connection
When using the USB connection, the device is identified by its index, starting from 0. To get the list of all the connected
devices, you can use Arcus.list_usb_performax_devices:
When using the RS-485 connection, you need to specify the serial port corresponding to your RS-485 connection and,
possibly, its baud rate:
The baud rate is 9600 by default, which is the standard value for the controllers. However, it can be changed using
Performax4EXStage.set_baudrate() method, in which case you would need to explicitly specify it during the
next connection.
In RS-485 mode idx parameter is still used, and it specifies the device number connected to this controller. By default
this number is 0, and it can be queried (using USB connection) via Performax4EXStage.get_device_number().
It can also be set using Performax4EXStage.set_device_number(), although the changes takes effect only after
the device is power cycled. Although in principle idx can be used to distinguish several Arcus controllers connected
to the same bus (i.e., sharing the same RS-485 COM port), currently only single device connection is supported.
To switch between USB and RS-485 control modes, you need to plug or unplug USB connection. It is strongly recom-
mended to power cycle the device after that, since otherwise it might stop responding to RS-485 commands.
Operation
This controller has several features and differences compared to most other stages and sliders:
• The 4-axis and 2-axis controllers are inherently multi-axis, hence they always take the axis as the first argument.
The axes are labeled with letters "x", "y" for a 2-axis version, or "x", "y", "z", "u" for a 4-axis one. The list
of all axes is related to the exact controller, an can be obtained using Performax4EXStage.get_all_axes().
A single-axis controller does not take an axis argument.
• Different axes can be enabled and disabled using Performax4EXStage.enable_axis(). Note that disabled
axes still behave the same as the enabled ones; e.g., their position will increment as usual, when move_to is
called. This can lead to some confusion, as the axis appears mostly operational, but the motor does not move.
• In the default controller configuration the limit errors are enabled. In this case, once a single axes reaches the limit
switch during motion, it is put into an error state, which immediately stops this an all other axes. Any further
motion command on this axis will raise an error, although it is still possible to restart motion on other axes.
The axis motion can only be resumed by calling Performax4EXStage.clear_limit_error(). If, however,
limit errors are disabled, then only the axis which reached the limit is stopped, and all other axes are unaffected.
Furthermore, the motion on the offending axis can be resumed without clearing its error status. In many cases the
default limit error behavior is undesirable, so the class turns it off upon connection. It can be subsequently turned
on and off using Performax4EXStage.enable_limit_errors(), and checked using Performax4EXStage.
limit_errors_enabled().
• Since simplified single-axis controller (DMX-J-SA) always has limit errors disabled, its behavior is specified a
bit differently. Upon connection you can specify autoclear argument (True by default), which indicates that
before every movement command the limit error should be automatically cleared.
• The controllers also have analog and digital inputs and digital outputs, which can be queried and set with the
corresponding commands.
• The controller has an option to connect an encoder for a separate position readout. By default, all of the com-
mands (e.g., for moving, getting position, getting current speed, etc.) still work in the step-counting mode,
and the encoder values are only accessed via Performax4EXStage.get_encoder()/Performax4EXStage.
set_encoder_reference(). In principle, there is a closed-loop mode call StepNLoop, but it is not currently
supported in the code.
• The built-in motion command has 2 modes: relative and absolute. The code sets the absolute mode on connection
and assumes it in all commands. However, if the mode changes for any reason, the move commands will stop
working properly.
Note: General stage communication concepts are described on the corresponding page
TMCM-x110 are universal stepper motor controller from Trinamic (currently Analog Devices), which include single-
axis TMCM-1110 and multi-axis TMCM-3110 and TMCM-6110. It provides multiple connection options, but so far
has only been tested with USB connection.
The main device classes are pylablib.devices.Trinamic.TMCMx110 for multi-axis devices and pylablib.
devices.Trinamic.TMCM1110 for a single-axis TMCM-1110 (TMCMx110 can also be used with TMCM-1110, but
many of the device variable will be dictionaries {axis: value} instead of single values).
Software requirements
USB connection needs drivers, which are supplied with the freely-available TMCL-IDE. With those drivers installed
(and even frequently already without them), the controllers show up as virtual COM ports. Note that when several
devices are connected, they sometimes get assigned conflicting (i.e., overlapping) COM ports. In this case, you might
need to manually reassign these in the Device Manager.
68 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Connection
Since the devices are identified as virtual COM ports, they use the standard connection method, and all you need to
know is their COM-port address (e.g., COM5):
Operation
This controller has several features and differences compared to most other stages and sliders:
• The controller allows one to control the number of microsteps per step using TMCM1110.
get_microstep_resolution() and TMCM1110.set_microstep_resolution(). Hence, the calibration
of the real position to the controller readout position depends on this resolution. Furthermore, changing this
resolution does not affect the step counter, meaning that changing it, performing a move, and changing it back
will result in a different position. Hence, it is not recommended to change it after homing or referencing the
position.
• Similarly, the controller has variable frequency divisors, which control the ratio between internal and real units
for the velocity and the acceleration. They are set up together with the maximal velocity and acceleration using
TMCM1110.setup_velocity() and TMCM1110.get_velocity_parameters(), and the conversion factors
can be obtained using TMCM1110.get_acceleration_factor() and TMCM1110.get_velocity_factor().
• The device has an option of controlling maximal output current using TMCM1110.setup_current() and
TMCM1110.get_current_parameters(). Change them carefully, since the values which are too large can
damage the motor. Also take into account, that the currents are defined relative to the maximal output current,
which is controlled using the physical jumper on the board (on TMCM-1110).
• The only real difference between pylablib.devices.Trinamic.TMCMx110 and pylablib.devices.
Trinamic.TMCM1110 is in how axis parameters are handled in device variables. In TMCM1110 the values are
turned as scalars, e.g., stage.dv["position"] can simply return 1234. In contrast, TMCMx110 returns dictio-
nary, so stage.dv["position"] will return {0: 1234}.
Note: General stage communication concepts are described on the corresponding page
SmarAct positioners
SmarAct has multiple different controller covering different slider kinds. So far only simple controllers (CU/HCU/SCU)
are implemented.
SmarAct CU/HCU/SCU
This is a simple controller, which is mostly aimed at open-loop (i.e., no position readout) positioners. It can control up
to 3 axes, and connects to the PC via the USB port.
The device class is pylablib.devices.SmarAct.SCU3D. Currently only open-loop controllers are supported.
Software requirements
The controller shows up as a virtual COM port, and it has a standard FTDI chip, so it does not need any special drivers.
However, to communicate with the device, it still needs SCU3DControl.dll library. It is supplied on a CD together
with the device, although it might also be possible to request it from SmarAct.
Connection
The devices are identified by their index starting from 0. To get the list of all the connected devices, you can use
SmarAct.list_scu_devices:
Due to the manufacturer’s API organization, it is currently only possible to “reserve” all connected stages of the same
type simultaneously in one application. This means that no other application can connect to any of the stages as long
as at least one stage is being controlled (though it does not make any difference if only one stage is connected).
In addition, currently there is no check on whether the stage is already controlled in the other part of the code. This
is in contrast with the vast majority of the devices, which issue a unique handle making it impossible to create two
different device objects even within the same application. Hence, one needs to be careful to not connect to the same
device twice, which can lead to confusing behavior.
Operation
This controller has several features and differences compared to most other stages and sliders:
• The motion is generally executed in “macrosteps”, which is a sequence of several “microsteps” with a given
amplitude, frequency, and number. A single macrostep with the defined parameters can be performed with
SCU3D.move_macrostep(), while SCU3D.move_by() executes a series of these macrosteps with one of the
predefined sizes (from 0 to 20). These sizes are configured to roughly correspond to the step sizes selectable by
the controller, although the agreement is not exact.
70 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
This is an advanced controller, which can control multiple open-loop and closed-loop stages using multiple sensor
modules. It connects to the PC via the USB or the Ethernet port.
The device class is pylablib.devices.SmarAct.MCS2. It has been tested with an Ethernet-connected MCS module
with several SLx stages.
Software requirements
The controller requires libraries supplied with the SmarAct MCS2 software, which is usually distributed with the
device. The required DLL is called SmarActCTL.dll and is located in the MCS2 folder (either MCS/SDK/lib64 for
64-bit systems). By default, pyLabLib searches for these DLLs in the default MCS2 software location (C:/SmarAct/
MCS2), in the folder defined by the corresponding environment variable upon installation (MCS2_SDK), as well as in the
folder containing the script. If the DLLs are located elsewhere, the path can be specified using the library parameter
devices/dlls/smaract_mcs2:
Connection
The devices are identified by their locator string, which may look like, e.g., "network:sn:MCS2-00000001" or
"usb:sn:MCS2-00000001". To get the list of all the connected devices, you can use SmarAct.list_mcs2_devices:
Operation
This controller has several features and differences compared to most other stages and sliders:
• The provided class implements the basic functionality required for the regular levels of automation: movement,
accessing position and status, setting up basic parameters (velocity, acceleration, step frequency, etc.), hom-
ing. However, it does not cover more advanced and rarely used functions like details of the sensor operation,
auxiliary IO, triggering, operation modes (normal, low noise, etc.), PID parameters, and so on. These can still
be accessed using MCS2.get_property() and MCS2.set_property() methods, but the interpretation of the
property values is up to the user.
Note: General stage communication concepts are described on the corresponding page
Physik Instrumente produces a variety of piezo, servo, and slider controller. So far, only PI E-515 and PI E-516 are
supported and tested via a standard serial connection.
The main device classes are pylablib.devices.PhysikInstrumente.PIE515 and pylablib.devices.
PhysikInstrumente.PIE516.
Software requirements
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Note that these devices frequently require cross-cable (also called null-modem cable), in which connections between
Rx and Tx lines are switched. In addition, one might need to activate RS-232 communication in the front panel menu,
as otherwise the device would not respond.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
These controllers has several features and differences compared to most other stages and sliders:
• The controllers support either servo (position feedback) or direct voltage output modes, controlled with PIE516.
enable_servo() method. In the servo mode they are more similar to a stage controller, and you can use, e.g.,
PIE516.move_to() and PIE516.stop() (only for E-516) methods. In the direct voltage mode you can use
PIE516.set_voltage() to set the voltage directly.
• The controllers only accepts commands from the PC when it is in the “online” (i.e., remote) mode, in
which case external voltage controls are ignored. This mode is enabled automatically upon connection if
auto_online=True is supplied upon creation (default), and can be connected via PIE516.enable_online()
method. Note that in this case manual servo switches should be turned off, since otherwise the device is perma-
nently in the servo mode.
• PI E-515 bring additional complications due to its mechanism of switching between the manual and online
modes:
– First, the online mode is only accessible when the servo mode switches on the front panel are off. At
the same time, even when online mode is not enabled (and the voltages/positions can not be controlled
remotely), it is still possible to switch the servo mode on and off remotely, so one must be careful when
calling PIE515.enable_servo().
– Second, when switching to the online mode, all of the voltages and positions are set to the last time they
were updated (or zero, if they have not been changed since the device was turned on). It is possible to set
the remote voltages to match the local ones before switching the modes, which is done automatically when
72 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
safe=True is supplied to PIE515.enable_online(). The same can not be done for servo positions,
since these can only be changed when the servo mode is on.
– Finally, when the online mode is turned back off, the output voltages go back to the values set by manual
knobs, which can be different from the current remote settings.
As a result, one should expect and look out for sudden changes in the stage positions when switching between
online and offline modes, and when switching the servo on and off.
Note: General stage communication concepts are described on the corresponding page
Standa produces a variety of motorized stages and positions, which are generally controlled by a single controller model
8SCM4 (older version) or 8SMC5 (newer version).
The main device class are pylablib.devices.Standa.Standa8SMC. The code has been tested with 8SMC4-USB
single-axis controller and 8MT167-25 stepper motor stage.
Software requirements
The controllers have a built-in USB-to-RS232 adapter, which is automatically recognized as a serial port by the OS, so
no additional software is required.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
This controller has several features and differences compared to most other stages and sliders:
• The controllers provide a large set of methods for checking and adjusting various motion parameters, controlling
different accessories, etc. So far only a basic subset of these commands is implemented, which allows one to
start and stop the motion, home the stage, set up basic velocity parameters, and query the status. If you need
advanced functionality, you can examine the list of commands in the documentation and implement them in your
code using Standa8SMC.query() method.
• All commands dealing with distances (e.g., moving, getting position, velocity, etc.) use internal units. For
DC motors these are steps (derived from the rotational encoder), while for stepper motors these are microsteps,
whose resolution can be found using Standa8SMC.get_stepper_motor_calibration(). This means that,
e.g., given a stepper motor with 200 steps per revolution and 256 microsteps per step, one can rotate it by a full
turn (before taking a possible gearbox into account) by calling stage.move_by(200*256).
• Some stages can come with a built-in linear encoder. In this case, the position can be accessed both us-
ing Standa8SMC.get_position() method like for all other stages, and using Standa8SMC.get_encoder()
method. If there is not linear encoder, Standa8SMC.get_encoder() will return zero.
Note: General device communication concepts are described on the corresponding page.
Basic example
Basic sensors usually only implement a handful of functions related to reading out the measurements (possibly on
different channels) and setting up measurements modes:
Here we talk more practically about using pylablib to perform commons sensor tasks.
74 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Readout
The main readout methods almost always start with get_ prefix, e.g., get_pressure, get_temperature, or
get_level. In some cases there would be two different measurement modes: one which just reads the latest mea-
surement result, and one which initializes the measurement, waits until it’s done, and returns the result. These two
approaches may be implemented differently in different devices, and it is addressed in their description:
Non-numerical values
In some cases the readout method would return a non-numerical values. This usually happens when the sensor readings
are outside of its range, or if it is in a wrong state (off, warming up, error, etc.) These cases are documented in the
querying method description:
Units
Unless absolutely necessary and obvious, all the readout values are specified in SI units (even, e.g., laser frequency
in Hz, or pressure in Pa). In rare cases when the devices allows for selection of readout units (e.g., Pfeiffer TPG260
gauges), it only affects the displayed value, but not the results returned by the corresponding methods:
Channel selection
Some gauges support simultaneous readout on several channels. In this case, all of their methods take an additional
channel (in most cases) argument, which specify the read channel.
The channels are usually specified by their index starting from 0 or 1, although some devices adopt more complicated
labeling schemes (e.g., Lakeshore 218 temperature sensor can only assign a sensor type to a group of 4 sensors, which
is labeled "A" or "B"). The exact specification is given in the specific class description.
• HighFinesse: laser wavelength meters. Tested with WS6 and WS7 USB-controlled devices.
• Ophir: optical power and energy meters. Tested with Ophir Vega.
• Thorlabs: optical power and energy meters. Tested with PM160.
• Lakeshore: temperature sensors. Tested with Lakeshore 218.
• Cryocon: temperature sensors. Tested with CryoCon 14C.
• Cryomagnetics: liquid nitrogen or helium level sensor. Tested with LM-500 and LM-510 sensors.
• Pfeiffer: pressure gauges. Tested with TPG261 and DPG202 controllers.
• Leybold: pressure gauges. Tested with ITR90 gauge.
• Kurt J. Lesker: pressure gauges. Tested with KJL300 gauge.
• Agilent: pressure gauges. Tested with XGS-600 controller and FRG700 gauge.
• Thorlabs quadrature detector controller. Tested with TPA101.
• Keithley multimeters. Tested with model 2110.
• Voltcraft multimeters. Tested with VC-7055BT and VC880.
Note: General sensor communication concepts are described on the corresponding page
HighFinesse wavemeters
HighFinesse produces a variety of fiber-coupled wavelength meters. Currently pylablib only deals with WS series
which uses a USB connection. The code has been tested with several WS6 and WS7 wavemeters.
The main device class is pylablib.devices.HighFinesse.WLM.
Software requirements
76 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Note: The control software should keep running the whole time. As soon as it is closed, the device will raise an error.
Finally, one needs the DLL to communicate with this software. It is usually named wlmData.dll, and it is located in the
main controller software folder either in Com-Test (for 32-bit applications) or Projects/64 (for 64-bit applications).
Connection
The device class makes an attempt to search for the DLL and executable in the standard installation folders, as well as
use the DLL in the standard location and its executable auto-detection capabilities. However, depending on the number
of installed wavemeters and their installation locations, one needs to provide up to 3 arguments on connection. First,
the wavemeter ID, which simply a 1 to 5-digit number (e.g. 1234). It is used to identify the correct instance of the
control software, either by searching for the correct folder, or via DLL autostart capabilities. Second, one might need to
provide the path to wlmData.dll (either including the name, or simply the containing folder). Its location is described
in the above section. Finally, you might also need to give the path to the application executable, which is located in
the main installation folder and is named wlm_ws*.exe, where * is the wavemeter generation (e.g., wlm_ws7.exe for
WS7 wavemeters). Hence, the fully qualified (and, therefore, most robust) instantiation looks like this:
>> import os
>> from pylablib.devices import HighFinesse
>> app_folder = r"C:\Program Files\HighFinesse\Wavelength Meter WS7 1234"
>> dll_path = os.path.join(app_folder, "Projects", "64")
>> app_path = os.path.join(app_folder, "wlm_ws7.exe")
>> wm = HighFinesse.WLM(1234, dll_path=dll_path, app_path=app_path)
>> wm.close()
A unique property of this device is the ability to control it simultaneously from several applications. Keep this in mind,
since it might cause confusion or strange results if the control attempts are not synchronized.
Warning: Communication with several simultaneously running wavemeters from a single application has not
been tested, and might not work correctly.
Operation
The operation of the wavemeter is fairly straightforward, but there is a couple of points to keep in mind:
• By default, the main measurement functions (WLM.get_frequency() and WLM.get_wavelength()) raise an
error on over- or under-exposure. If this is undesirable (e.g., the laser has power jumps), one can instead make it
return "over" or "under" on these occasions.
• The measurement result is returned immediately, but it is updated only about every 15-30ms (+ exposure time).
Hence, fast consecutive calls to WLM.get_frequency() and WLM.get_wavelength() will return the same
value.
• Multi-channel devices have two working modes: single-channel (when only one channel is enabled at a time)
and cycling (the wavemeter constantly cycles through several channels for quasi-simultaneous measurements).
Some methods only make sense in one of this modes, e.g., WLM.set_active_channel() only works in the
single-channel mode, while WLM.enable_switcher_channel() only in the multi-channel mode. By default,
these methods will automatically switch to the corresponding mode.
• Due to a minor control software bug, change in the exposure on some channels might not be reported until
the control software is switched to the corresponding channel’s exposure control tab (in the upper right cor-
ner). By default, the device class performs this switching any time the exposure value is queried, which solves
the issue. However, it does take about 10ms. If it is critical, it’s possible to turn of this behavior by setting
auto_channel_tab attribute to False.
Note: General sensor communication concepts are described on the corresponding page
Ophir produces a variety of power and energy meters with different controllers and measurement heads. The class has
been tested with Ophir Vega controller with a photodiode head.
The main device classes are pylablib.devices.Ophir.OphirDevice for a generic device and pylablib.
devices.Ophir.VegaPowerMeter for Vega power meter.
Software requirements
The device provides a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5) and the baudrate, if it is different from the standard one (9600 baud):
>> meter1.close()
>> meter2.close()
Operation
The operation of the power meter is fairly straightforward, but there is a couple of points to keep in mind:
• On the Vega controller the results can be sent at most 15 times a second. However, they are not necessarily
updated at this rate, so several consecutive request might yield the same result.
• The device provides the way to change the communication baud rate. If the rate is changed, the device is auto-
matically disconnected, and the new object needs to be instantiated with the updated baudrate.
• The device might return "over" instead of the power reading on overexposure. To fix that, you can adjust the
measurement range using VegaPowerMeter.set_range_idx().
Note: General sensor communication concepts are described on the corresponding page
78 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Thorlabs produces several different models of power and energy meters with different controllers and measurement
heads, but relatively similar interfaces. The class has been tested with PM160 standalone power VegaPowerMeter.
The main device class pylablib.devices.Thorlabs.PM160.
Software requirements
The drivers for USB devices are provided in the Thorlabs Optical Power Monitor software software. PyLabLib uses
NI VISA communication interface to communicate with this device. Hence, it also requires NI VISA Runtime, which
is freely available from the National Instruments website. Finally, to make the devices run with VISA interface, you
need to run Power Meter Driver Switcher (comes with the Optical Power Monitor software) and switch all the desired
power meters to PM100D mode (it is called PM100D even for other power meters such as PM160).
Devices with pure RS232 interface do not require Thorlabs software, and only need an appropriate USB-to-RS232
adapter with its own drivers.
Devices with bluetooth connection can be used on Windows via a bluetooth COM port. For that, first you need co
connect the power meter to your PC by making sure it is active (i.e., the display is lit up), and then adding a new bluetooth
device in Bluetooth and other devices settings (the power meter should show up in the list of discovered
devices). After that, you need to open More Bluetooth options (in the panel on the right side) and navigate to the
COM Ports tab. There should already be several COM ports in the list corresponding to the added power meter. You
are interested in the one marked with Outgoing direction, with the name containing 'SPP' (e.g., Thorlabs PM160
400000 'SPP'). The corresponding COM port (e.g., COM5) is the one you need to use for communication.
Connection
Depending on the protocol used (VISA or RS232/bluetooth), you will need to supply either a VISA name (e.g.,
"USB0::0x1313::0x807B::400000::INSTR") or a COM port name (e.g., "COM5"), potentially with the baud rate if
it is different from the standard 115200 baud (e.g., ("COM5", 19200); only applies to RS232 devices, not bluetooth):
Operation
The operation of the power meter is fairly straightforward, but there is a couple of points to keep in mind:
• Bluetooth communication tends to go to a sleep mode after about a second of inactivity (i.e., lack of communi-
cation with the PC). When in this mode, it takes about a second for the device to reply to the first command, after
which it switches in the active mode and replies significantly fast (about 20ms per command) until it goes back
into the sleep mode. Hence, to keep the device responsive, it is important to poll it at least 2-3 times a second
(e.g., using method PM160.get_reading() with measure=False, which immediately returns the currently
displayed value).
Note: Basic sensors communication concepts are described on the corresponding page
Lakeshore manufactures a range of temperature sensor controllers and resistance bridges, which are also used for
temperature sensing. There is some overlap between different products, but they still use fairly distinct interfaces and
interaction patterns. The code has been tested with Lakeshore 218 temperature controller.
The main device class is pylablib.devices.Lakeshore.Lakeshore218.
Software requirements
The device provides a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Note that the connection uses the standard which is fairly different from most RS232 controllers: 7 data bits, 1 parity
bit, and 1 stop bit (as opposed to 8 data bits and no parity bit for most controllers). Hence, it is possible that not all
RS232 controllers can communicate with it. In addition, they might need a null-modem (crossed Rx and Tx lines)
RS232 cable.
Operation
The operation of this temperature sensor is fairly straightforward, but there is a couple of points to keep in mind:
• Like most similar devices, querying temperature using Lakeshore218.get_temperature() immediately re-
turns the most recently measured value. Re-measurement is periodically initiated by the devices itself.
• It is possible to specify custom response curves by using Lakeshore218.set_curve_header() and
Lakeshore218.set_curve(). However, you need to be careful, as it overwrites the stored user curves.
Note: Basic sensors communication concepts are described on the corresponding page
CryoCon manufactures a range of temperature sensor controllers and resistance bridges, which are also used for tem-
perature sensing. The code has been tested with CryoCon 14C temperature controller.
The main device class is pylablib.devices.Cryocon.Cryocon1x.
80 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
The device provides a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
The operation of this temperature sensor is fairly straightforward, but there is a couple of points to keep in mind:
• Like most similar devices, querying temperature using Cryocon1x.get_temperature() immediately returns
the most recently measured value. Re-measurement is periodically initiated by the devices itself.
Note: Basic sensors communication concepts are described on the corresponding page
Cryomagnetics manufactures cryogenic liquid level monitors, which are used for monitoring liquid nitrogen or helium
levels inside cryostats. The two level meters supported in the package are LM-500 and LM-510; despite difference in
appearance, their functionalities are very similar, so their interfaces are nearly identical.
The main device classes are pylablib.devices.Cryomagnetics.LM500 and pylablib.devices.
Cryomagnetics.LM500.
Software requirements
LM-500 provides a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work. LM-510 has a USB
interface with a built-in USB-to-RS232 adapter, which is automatically recognized as a serial port, so no additional
software is required.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
The operation of this temperature sensor is fairly straightforward, but there is a couple of points to keep in mind:
• Upon connection the devices are automatically switched into the remote mode, which disables manual controls.
If this mode is manually switched off (e.g., using Local button in LM-510), the device will no longer obey the
remote commands, even though the readout would still work.
• There are no specific commands for stopping a refill or resetting the timeout state after a timed-out refill. However,
both can be achieved using LM500.reset() method.
• Only LM-510 supports switching the automated refill option on and off using LM510.set_control_mode()
method.
• Like most similar devices, querying the level using LM500.get_level() immediately returns the most recently
measured value. Re-measurement is periodically initiated by the devices itself, or can be initiated manually using
LM500.start_measurement() or LM500.measure_level().
Note: Basic sensors communication concepts are described on the corresponding page
Pfeiffer manufactures a range of pressure gauges and controllers with several different standards and communication
protocols. The code has been tested with Pfeiffer TPG260 series controller (specifically, TPG261) and Pfeiffer DPG202
controller.
The main device classes are pylablib.devices.Pfeiffer.TPG260 and pylablib.devices.Pfeiffer.DPG202.
Software requirements
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
TPG260 series
The operation of this gauge is fairly straightforward, but there is a couple of points to keep in mind:
• On measurement error TPG260.get_pressure() returns None. To get the underlying issue, you can use
TPG260.get_channel_status()
82 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
• By default, the pressure is always returned in Pa regardless of the display units. This behavior can be overridden
by setting display_units=True in TPG260.get_pressure().
• In case an error occurs, you can use TPG260.get_current_errors() to get the list of currently active errors
and TPG260.reset_error() to reset them.
• This communication protocol for 350-series gauges (361, 362 and 366) is similar, so the device class should also
be able to work with them. However, it has not been tested.
DPG202/TPG202 controller
There is a variety of different controllers which implement a similar protocol: DPG202 and TPG202, as well as a variety
of RS485-controlled gauges (e.g., CPT200). It is based on requesting parameters with certain 3-digit numbers. These
are fairly consistent between the devices, for example, 312 stands for the software version, 740 for pressure, and 349
for the device name. However, different devices implement different subsets of these parameters. The supplied class
provides a generic interface through DPG202.get_value() and DPG202.comm() methods, which, correspondingly,
request or set a value of a given parameter given its number (e.g., 740) and datatype (e.g., "string", "u_expo_new",
or "u_short_int"). Both of these pieces of information are usually provided in the controller or gauge manual
in the Parameter overview (or similar-named) section. Currently the device class provides only the most basic
functionality:
9.78E2
>> gauge.close()
Note: Basic sensors communication concepts are described on the corresponding page
Leybold manufactures a range of pressure gauges and controllers with several different standards and communication
protocols. The code has been tested with Leybold ITR90 pressure gauge using its built-in RS232 connection.
The main device classes are pylablib.devices.Leybold.ITR90.
Software requirements
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
ITR90
The operation of this gauge is fairly straightforward, but there is a couple of points to keep in mind:
• Device operates by constantly streaming its status updates. To get the most recent and most consistent data, you
can use ITR90.get_update(). This is also how you access the gauge status and error states.
• By default, the pressure is always returned in Pa regardless of the display units. This behavior can be overridden
by setting display_units=True in ITR90.get_pressure().
Note: Basic sensors communication concepts are described on the corresponding page
KJL manufactures a range of pressure gauges and controllers with several different standards and communication pro-
tocols. The code has been tested with KJL300 pressure gauge using its built-in RS232 connection.
The main device classes are pylablib.devices.KJL.KJL300.
Software requirements
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
84 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
KJL300
The operation of this gauge is fairly straightforward, but there is a couple of points to keep in mind:
• Even standard RS232 operation requires specifying the device RS485 address. IT can be specified using addr
parameter on creation. By default, the class assumes the factory default of 1, but if it is ever changed on the
device, it needs to be specified correctly.
• By default, the pressure is always returned and set in Pa regardless of the display units.
Note: Basic sensors communication concepts are described on the corresponding page
Among other things, Agilent manufactures a range of pressure gauges and controllers. The code has been tested with
Agilent XGS-600 controller with an analog board and FRG700 gauge.
The main device class is pylablib.devices.Agilent.XGS600.
Software requirements
The devices provide a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
The operation of this controller is fairly straightforward, but there is a couple of points to keep in mind:
• The list of pressures returned by XGS600.get_all_pressures() only includes the installed boards, so it will
changed when boards are installed or removed. On the other hand, the order does not depend on whether gauges
are connected, since it return "nocbl" for any connectors without gauges.
• By default, the pressure is always returned in Pa regardless of the display units. This behavior can be overridden
by setting display_units=True in XGS600.get_all_pressures().
Note: General device communication concepts are described on the corresponding page.
Basic example
Basic lasers (such as pump lasers) usually only have very basic power-related functionality: turning it on and off, setting
power, and controlling and/or requesting the shutter state:
Lighthouse Photonics Sprout laser implements the same basic functionality, with some small additions like reading the
interlock status, output mode, temperatures, etc.
The device class is pylablib.devices.LighthousePhotonics.SproutG.
Since the device shows up as a COM port, it uses the standard connection method, and all you need to know to connect
is its COM-port address:
Laser Quantum Finesse laser implements the same basic functionality, with some small additions like controlling the
shutter, reading the driving current, temperatures, etc.
The device class is pylablib.devices.LaserQuantum.Finesse.
Since the device shows up as a COM port, it uses the standard connection method, and all you need to know to connect
is its COM-port address:
Note: General device communication concepts are described on the corresponding page.
86 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Solstis is a Ti:Saph laser produces by M2. It is controlled via IceBloc controller unit, which communicates with the
PC via a network connection.
The main laser class is pylablib.devices.M2.Solstis.
Software requirements
The device provides a bare network interface, so no additional software is required. However, the device and the local
network need to be appropriately configured, such that the PC and the laser are in the same local network and have
static IPs.
In order to access some advanced features, you will need a websocket-client package, which is not installed with
pylablib by default. You can obtain it from PyPi either separately as
Connection
The laser is identified by its IP address (typically starting with 192.168.1, if it is on the local network) and the port:
The port is set up in the Remote interface row of the Network Settings menu of the laser web interface. There
you also need to provide the correct IP address of the controlling PC and enable the remote interface; otherwise the
connection will be rejected by the laser.
In addition, you can enable websocket interface option, which is used to send request directly though the device web
interface. It is used for some options which are unavailable otherwise, such as enabling or disable the wavemeter
connection, receiving some additional status information, and performing more robust control. Note that for proper
operation the web interfaces should be opened in the browser and logged in.
Operation
The method names are pretty self-explanatory, and mostly correspond directly to the operations in the web inter-
face. Note that, due to the remote interface organization, terascan requires two methods to start: first Solstis.
setup_terascan() to specify parameters, and then Solstis.start_terascan() to start it.
One should note, that the device operation is not very stable, and occasionally some errors and crashes arise. These
can range from failed wavelength tuning and terascan, to terascans failing in exotic ways (e.g., the remote interface
suggests that the scan is in progress while the web interface reports a crash), to complete device failure requiring Ice
Bloc power cycling.
The device class attempts to somewhat mitigate it by providing relatively a robust stopping method Solstis.
stop_all_operation(), which tries to set the devices to the default idle state. It uses web interface to get a better
information about the laser crashing and send additional stopping commands. It also performs additional steps to stop
scans and put the laser in an operation state after a failure, such as starting quick small fine and terascans, and tuning
to a nearby frequency.
M2 EMM allows for mixing Solstis lasers with an additional IR laser to produce higher frequency radiation. Its control
principles are fairly similar to Solstis, and it is accessed through the same kind of Ice Bloc controller.
The main device class is pylablib.devices.M2.EMM.
Software requirements
Same as Solstis, the device provides a bare network interface, so no additional software is required. However, the
device and the local network need to be appropriately configured, such that the PC, the EMM, and the corresponding
Solstis laser are in the same local network and have static IPs.
Connection
The EMM is identified by its IP address (typically starting with 192.168.1, if it is on the local network) and the port:
The port is set up in the Remote interface row of the Network Settings menu of the controller web interface.
There you also need to provide the correct IP address of the controlling PC and enable the remote interface; otherwise
the connection will be rejected by the controller.
Operation
The methods are organized in the same way as for the Solstis laser. Overall, the remote interface implements fewer
commands, so the class provides fewer methods. Most of the commonly used methods are related to fine frequency
tuning, terascan control, and status checking.
Note: General device communication concepts are described on the corresponding page.
Toptica iBeam Smart is a series of CW diode lasers from Toptica. The software has been tested with the standard
633nm laser.
The main device class is pylablib.devices.Toptica.TopticaIBeam.
Software requirements
The device is connected to the PC via RS232 or USB. RS232 simply requires a COM-port controller on the PC, which
in most cases is a USB-to-Serial adapter. Such adapters normally come with their standard drivers. The USB version
simply involves a built-in USB-to-Serial converter (e.g., a standard FTDI chip), so it also shows up as a virtual COM
port. Hence, it requires relatively standard drivers, which are either included with the laser, or can be download from
the manufacturer’s website, for example, together with the TOPAS control software.
88 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Connection
Since the devices are identified as virtual COM ports, they use the standard connection method, and all you need to
know is their COM-port address (e.g., COM5) and, possibly, baud rate, if it is different from the standard 115200 baud:
Operation
Usually the laser has the main power control and one or several (up to 5) output channels, which can be controlled
separately. To turn the whole laser on or off, you can use TopticaIBeam.enable(), while each channel is controlled
using TopticaIBeam.enable_channel(). The power is set independently for each channel via TopticaIBeam.
set_channel_power(). The actual output power can be queried using TopticaIBeam.get_output_power().
Detailed info
The most detailed information about the laser can be obtained using TopticaIBeam.get_full_data() method. It
outputs a detailed report generated by the laser, which contains most of the adjustable parameters.
Occasionally the laser communication falls into an error state, where replies are lagging behind the requests (i.e., instead
of replying to the issued command, the devices replies to the previous one). This is especially likely if several commands
are issued in a rapid succession. If this happens, the laser should be rebooted using TopticaIBeam.reboot() method.
Note: General device communication concepts are described on the corresponding page.
Software requirements
The device requires Matisse Commander software supplied by the manufacturer. When it is installed, it shows up as a
VISA resource and can be accessed without further requirements.
Connection
The laser is identified by its VISA address, typically looking like "USB0::0x17E7::0x0102::01-01-10::INSTR":
Alternatively, one can use a network connection to the Matisse Commander server, if it is enabled in the Matisse
Commander communication Options:
>> laser.close()
Operation
The method names are pretty self-explanatory, and mostly correspond directly to the operations in the Matisse Com-
mander. However, only the basic tuning and scanning functions supplied by the interface are provided, and the more
advanced once like scanning BRF/etalon or interfacing with a wavemeter need to be implemented by the user based on
the defined methods.
Note that depending on the specific model not all methods are available, e.g., reference cell locking is not available in
TR/DR configuration.
Note: General device communication concepts are described on the corresponding page.
NKT Photonics produces a variety of light sources (predominantly fiber-coupled lasers), which are frequently ar-
ranges as multi-stage modular systems. These systems consist of individual modules, which can be controlled
via the main module using the common Interbus connection. The main laser class is pylablib.devices.NKT.
GenericInterbusDevice for a generic Interbus-connected system. The code has been tested with SuperK EX-
TREME white light laser equipped with SuperK SELECT tunable filter.
90 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
The controllers have a built-in USB-to-RS232 adapter, which is automatically recognized as a serial port by the OS, so
no additional software is required. If the device is not recognized, the drivers can be obtained from the manufacturer
website.
Connection
The whole Interbus system is identified as a COM port, so it uses the standard connection method, and all you need to
know is its COM-port address (e.g., COM5):
Within each Interbus system, there is a set of modules which can be accessed individually using their address (a
number between 1 and 48). To automatically detect all available modules, you can use GenericInterbusDevice.
ib_scan_devices(). Note that it typically takes relatively long time (about 25s for the full scan), so you should
generally only do it when you change the Interbus arrangement by connecting or disconnecting devices or changing
their addresses.
To identify, which address corresponds to which device, there are several methods. First, you can use the returned device
type (also an integer between 0 and 255). You can look up the types in the SDK manual, which is freely available on
the manufacturer website (you need to download SDK zip file, inside which SDK Instruction manual.pdf provides
the necessary information). In addition, some devices either have standard addresses (e.g., Koheras BasiK K80-1 has
address 10 and type 33, while SuperK EXTREME has address 15 and type 96), or allow for setting their address using
switches (e.g., SuperK SELECT).
Operation
All of the device control is done by querying and setting values of internal registers. Similar to modules them-
selves, registers within each module are also identified by their numerical addresses. The list of the device regis-
ters and their meaning is provided in the same SDK file as mentioned above. To access the registers, you can use
GenericInterbusDevice.ib_get_reg() and GenericInterbusDevice.ib_set_reg() methods. By default
these methods work with raw binary values, but you can provide the register kind (e.g., "i16" or "u8") to these
methods. You can learn the kind of the registers and their precise meaning from the register files, which are available
after installing the SDK. These files are located in the Register Files folder within the SDK, and their names cor-
respond to the device kind in hex (e.g., the file corresponding to Koheras BasiK K80-1 will be name 21.txt). Given
this information, you can control your system. For example, the following code connects to the SuperK EXTREME
module, queries its inlet temperature, sets the power setpoint and turns on the emission:
Note: General device communication concepts are described on the corresponding page.
Cobolt is a series of diode and diode-pumped lasers produces by Hubner Photonics. They might have several con-
nection options (e.g., USB or direct serial RS232), but they implement the same command protocol and can be used
interchangeably. The code has been tested with Cobolt 06-01 series laser using a USB connection,
The main laser class is pylablib.devices.Hubner.Cobolt.
Software requirements
When using a bare RS232 interface, any appropriate USB-to-RS232 adapter should work. When using a USB connec-
tion, one might need to install manufacturer-provided drivers. In any case, the device will be identified by the OS as a
serial port.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
The method names are pretty self-explanatory. The device typically lets one enable or disable the output, query key
switch and interlock status, set up the operation mode (constant power/current, modulation, etc.), set up output power
or current, and query some statistics (temperatures, operation hours, LED states). Note that, depending on the model,
not all methods are supported.
Note: General device communication concepts are described on the corresponding page.
Tektronix produces a large number of very widespread oscilloscopes. They have strongly overlapping, though not
entirely identical, interfaces. The library has been tested with TDS2002B, TDS2004B, and DBO2014B.
The generic oscilloscope class is pylablib.devices.Tektronix.ITektronixScope, and the derived classes
for specific devices are pylablib.devices.Tektronix.TDS2000 of TDS2000 series and pylablib.devices.
Tektronix.DPO2000 for DPO2000/MSO2000 series.
92 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Software requirements
These oscilloscopes use NI VISA communication interface. Hence, it requires NI VISA Runtime, which is freely
available from the National Instruments website
Connection
The devices are identified by their VISA connection strings, which typically start with USB0::0x0699, e.g.,
"USB0::0x0699::0x0364::C000001::INSTR". To get a list of all connected VISA-enabled devices, you can run
pylablib.list_backend_resources("visa"):
Operation
The method names are usually pretty self-explanatory. A typical operation involves setting up channels, scales, and
trigger options, acquiring a waveform, and reading the result:
data (vertical and horizontal scales and offsets, data format, etc.) to translate into physical units. By default, it is
acquired every time before the waveform transfer, which takes some time (up to ~200ms). Alternatively, one can
acquire a preamble once and use it in subsequent reading. This method is faster, but will result in an incorrect
scaling if the parameters are changed in the meantime (either remotely, or directly on the oscilloscope):
• The device class attempts to determine the number of channels automatically on connection, based on which
requests raise device errors. However, this process takes some time, and sometimes can raise errors on not fully
SCPI-compliant devices. If that is the case, it is always possible to supply the number of channels on construction:
>> osc.get_channels_number()
2
>> osc.close()
>> osc = Tektronix.TDS2000("USB0::0x0699::0x0364::C000001::INSTR", nchannels=2) #␣
˓→specify manually
Keithley (currently absorbed by Tektronix) manufactures a large variety of precision electrical test and measurement
equipment.
Note: Basic sensors communication concepts are described on the corresponding page
There are different series of multimeters with somewhat different capabilities. The code has been tested with Keithley
2110 multimeter, but it should also be able to work with 2100 and 2010 series.
The main device class is pylablib.devices.Keithley.Keithley2110.
Software requirements
These multimeters use NI VISA communication interface. Hence, it requires NI VISA Runtime, which is freely avail-
able from the National Instruments website
Connection
The devices are identified by their VISA connection strings, which typically start with USB0::0x05E6, e.g.,
"USB0::0x05E6::0x2110::0000001::INSTR". To get a list of all connected VISA-enabled devices, you can run
pylablib.list_backend_resources("visa"):
94 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
The operation of this multimeter is fairly straightforward, but there is a couple of points to keep in mind:
• While all measurement modes are, in principle, supported, only some of them have implemented specific param-
eter changing (e.g., range or resolution): voltage and current (AC and DC), resistance (2-wire and 4-wire), ca-
pacitance, frequency and period (voltage and current). These methods allow for changing of specific parameters
using methods like Keithley2110.get_vcr_function_parameters() (get voltage, current, or resistance
measurement parameters) or Keithley2110.set_cap_function_parameters() (set capacitance measure-
ment parameters).
• At the same time, more universal Keithley2110.get_configuration() and Keithley2110.
set_configuration() methods allow for changing basic parameters (range and resolution) for all of
the applicable measurement functions (excluded are continuity, diode, and temperature modes).
Rigol manufactures a large variety of electrical test and measurement equipment, including signal generators, oscillo-
scopes, multimeters, power supplies, etc.
There are different kinds of power supplies with somewhat different capabilities. The code has been tested with Rigol
DP1116A.
The main device class is pylablib.devices.Rigol.DP1116A.
Software requirements
These power supplies use NI VISA communication interface. Hence, it requires NI VISA Runtime, which is freely
available from the National Instruments website
Connection
The devices are identified by their VISA connection strings, which typically start with USB0::0x1AB1, e.g.,
"USB0::0x1AB1::0x0E10::DP1A000000000::INSTR". To get a list of all connected VISA-enabled devices, you
can run pylablib.list_backend_resources("visa"):
Operation
The operation of this multimeter is fairly straightforward, but there is are some points to keep in mind:
• Note that the supply supports different output ranges (for DP1116A it’s "16V" or "32V"), which trike different
balance between output voltage and current. Other power supplies might support different output ranges, in
which case the related method will raise an error or lead to communication timeout.
Note: General device communication concepts are described on the corresponding page.
National Instruments produces lots of different data acquisition devices, which support digital and analog input and
output, both immediate and clocked (depending on the exact device). They are controlled via a very universal NI
DAQmx interface. This interface is implemented in python-nidaqmx package, which provides a fairly close to original
functionality, but with much more convenient Python wrappers. Pylablib implements a relatively thin wrapper around
this package to present it in a way similar to the other device classes, and to simplify common tasks such as setting up
voltage and counter input channels.
The main daq class is pylablib.devices.NI.NIDAQ . It has been tested with NI PCIe-6323, NI USB-6008, and NI
USB-6363.
Software requirements
This interface uses NI DAQmx library, which is freely available on the National Instruments website. Additionally,
it needs python-nidaqmx package (not to be confused with pydaqmx). It is not automatically installed with the base
version of pylablib, and can be obtained from PyPi either separately as
Connection
The devices are identified by their name, such as "Dev1". To list all of the connected devices together with their basic
information, you can run NI.list_nidaqmx_devices:
96 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
Operation
The typical use case involves setting up different input and output channels, starting acquisition, and acquiring some
number of samples:
daq.add_digital_input("din", "port0/line0")
daq.setup_clock(100) # setup 100Hz sampling clock
trace = daq.read(100) # start acquisition, read finite number of samples, and stop it␣
˓→again
The class provide basic methods to set up analog, digital, and counter inputs, and analog and digital outputs. All the
analog and digital inputs are synchronized to the same clock, which is the default analog input sample clock (ai/
SampleClock) by default. It is also possible to set up the external clock via NIDAQ.setup_clock() and export the
sampling clock via NIDAQ.export_clock(). Not that not all devices support clocked digital inputs, which means
that setting up digital inputs there would raise an error.
By default, the counter inputs are synchronized to the same clock, although it is possible to change that. The counter
inputs have 3 modes for output values: bare counter (accumulates the number of counts), differential (number of new
counts between the two sampling points), and rate (same as differential, but normalized by the sampling rate). In case
of external clock, when the sampling rate is a priori unknown, it might be useful to setup a clock rate counter input to
determine this clock rate via NIDAQ.add_clock_period_input().
Acquisition is controlled with NIDAQ.start() and NIDAQ.stop() methods, and the readout is performed via NIDAQ.
read(). The result of this is always a 2D numpy array, where the first index corresponds to samples and the second to
channels. The order of channels can be obtained from NIDAQ.get_input_channels().
The outputs can be either analog or digital. The digital outputs are always immediate, i.e., they immediately produce
and hold the latest output value. The analog outputs can work in two modes: either immediate, or clocked. The mode
is set up via NIDAQ.setup_voltage_output_clock(). In this case, it is possible to output a list of values, which
produces a waveform clocked according to the specified clock: either a separate clock source (default), or the analog
input clock, which makes voltage input and output synchronized.
Note: General device communication concepts are described on the corresponding page.
There is a large variety of Arbitrary Waveform Generators, which have very similar characteristics and communication
interface.
The generic AWG class is pylablib.devices.AWG.GenericAWG, and the derived classes for specific devices
are pylablib.devices.AWG.Agilent33500 and pylablib.devices.AWG.Agilent33220A for two different
Agilent AWGs, pylablib.devices.AWG.RigolDG1000 for Rigol DG1000 series, pylablib.devices.AWG.
TektronixAFG1000 for Tektronix AFG1000 series, pylablib.devices.AWG.InstekAFG2000 for Instek GW 2000
series, pylablib.devices.AWG.RSInstekAFG21000 for Iso-Tech 21000 series (a clone of Instek AFG2000, but with
a couple of bugs which needs to be worked around), and pylablib.devices.AWG.InstekAFG2225 for Instek GW
2225 (slightly advanced two-channel version of Instek AFG2000).
Software requirements
Most of these AWGs use NI VISA communication interface. Hence, they require NI VISA Runtime, which is freely
available from the National Instruments website. However, Instek and Iso-Tech AWGs show up as virtual COM ports,
so they require no additional software.
Connection
The devices are identified by their VISA connection strings, (e.g., "USB0::0x0699::0x0364::C000001::INSTR")
or COM-port (e.g., "COM5"). To get a list of all connected VISA-enabled devices, you can run pylablib.
list_backend_resources("visa"):
Operation
The method names are usually pretty self-explanatory. A typical operation involves setting up the function, its param-
eters, and controlling output:
98 Chapter 2. Citation
pylablib Documentation, Release 1.4.3
• Similarly, some methods can be present but not applicable to the particular AWG (e.g., burst trigger related
methods, phase synchronization methods, etc.) If this is the case, they will cause an error when called.
Note: General device communication concepts are described on the corresponding page.
In addition to cameras, Andor has a set of spectrometers primarily designed to work with and communicate through
those cameras. Among these Kymera and Shamrock spectrographs have a common configuration and API.
The code is located in pylablib.devices.Andor, and the main device class is pylablib.devices.Andor.
ShamrockSpectrograph . It has been tested with Kymera 328i spectrograph connected via an Andor Newton camera
through I2C interface.
Software requirements
Unfortunately, there is a large variety of different hardware setups and DLL combinations, which relate to each other
in very non-obvious way. The possible adjustable parameters are
• Spectrograph connection: either via camera’s I2C interface, or directly to the PC via a USB interface
• Camera AndorSDK2 DLL: on 64-bit systems it can be named atmcd64d.dll or atmcd64d_legacy.dll, and
it can come from Andor Solis or Andor SDK2.
• Spectrometer DLL; on 64-bit systems it can be named atspectrograph.dll, ShamrockCIF.dll, or
ShamrockCIF64.dll, and it might require Andor SDK2 DLLs (atmcd64d.dll, atmcd64d_legacy.dll,
atshamrock.dll, atshamrock64.dll) to be located in the same folder. it can come from Andor Solis, Andor
SDK2 or MicroManager plugin available on Andor/Oxford website.
As mentioned above, there are three main sources of these libraries:
• Andor Solis, which can be obtained either with the camera, or from the website upon registration.
• Andor SDK2, similarly obtained from the website (the most recent version is 2.104.30084)
• MicroManager plugin, also obtained from the website (Software section; here is the direct link).
In general, it makes sense to try different combinations of DLLs and connection methods and see what works. To specify
the exact DLL sources, you use the corresponding library parameters devices/dlls/andor_sdk2 and devices/
dlls/andor_shamrock:
• Not being able to find camera, spectrograph, or both. You can check for this by examining the outputs of Andor.
get_cameras_number_SDK2() and Andor.list_shamrock_spectrographs()
• Not being able to connect both to the camera and the spectrograph simultaneously. It might be possible to connect
to one of them individually, but once one connection is opened, the other one gets blocked. You can check for
this directly by trying to open both the camera and the spectrograph and making sure that it works (if it does
not, it will look the same as if the camera/spectrograph disappear as soon as spectrograph/camera is connected).
It might be less of an issue if the spectrograph is connected directly via USB rather than via I2C through the
camera.
• In some cases (especially when using libraries from the MicroManager plugin), spectrograph is identified cor-
rectly and can be connected to, but the connection is corrupted, and queries return nonsense values.
• Rarely, the spectrometer state might get corrupted, and it would stop being identified even in Andor Solis. In
this case, you can try power cycling the spectrometer, camera and PC, as well as temporarily changing the
spectrometer connection method (USB generally seems more stable). Just as a precaution, it is recommended
to store a backup of the spectrograph EEPROM configuration, which can be done through Andor Solis. To do
that, you need to go to the Hardware -> Spectrograph Setup window in the top menu, there click on the
System Configuration button, and there export the EEPROM state via Save to File... button.
Connection
The spectrographs are identified by their index, starting from zero. To list the connected spectrographs, you can run
Andor.list_shamrock_spectrographs:
In addition, in order to acquire the spectra you need to establish the connection to the corresponding camera using
Andor cameras interface. It is generally recommended to open the camera connection before the spectrograph to avoid
software conflicts.
Operation
The operation of these spectrographs is relatively straightforward. Note that they only allow for control of the spectrom-
eter part of the setup (e.g., gratings, slits, filters) and for calculation of the wavelength calibration, i.e., the wavelength
corresponding to each camera pixel column. In order to actually acquire and image, you would need to establish a
separate camera connection and acquire images from it independently (typically in the full vertical binning, FVB,
mode):
>> cam.set_image_mode("fvb")
>> spectrum = cam.snap()[0] # 1D array of the corresponding spectrum intensities
(continues on next page)
Note: General device communication concepts are described on the corresponding page.
Thorlabs has a variety of devices implementing different serial communication protocols, mostly related to optome-
chanics. Their requirements and general approach are still fairly similar, so they are all collected here.
Software requirements
Most devices provide either a bare RS232 interface, or a USB connection with a built-in USB-to-RS232 chip. In either
case, they are automatically recognized as serial ports, and no additional software is required. The only exception on
this page is MFF101/102 motorized flip mount, which belongs to the Kinesis devices and requires APT software.
Connection
Most of the devices are identified as COM ports, so they use the standard connection method, and all you need to know
is their COM-port address (e.g., COM5):
The only exception is MFF101/102, which is identified by its serial number (more details are given at the Kinesis
devices page).
Operation
The class is provided as pylablib.devices.Thorlabs.MFF. It allows for control of the flip mirror position, as well
as changing its motion parameters and designations of its digital input and output.
Note that older version (1.0) of the filter wheel do not support the full range of options and operate on a slightly different
protocol. This leads to crashes on at least some of the methods, e.g., FW.get_position(). If this is the case, you can
try pylablib.devices.Thorlabs.FWv1 instead.
Note: General device communication concepts are described on the corresponding page.
OZ Optics provides a variety of mostly fiber-optics related devices. Pylablib covers some of its fiber optomechanics
solutions: polarization controller, tunable filter and variable attenuator. Their requirements and general approach are
fairly similar, so they are all collected here.
Software requirements
All the devices provide either a bare RS232 interface, or a USB connection with built-in USB-to-RS232 chip. In either
case, they are automatically recognized as serial ports, and no additional software is required.
Connection
The devices are identified as COM ports, so they use the standard connection method, and all you need to know is their
COM-port address (e.g., COM5):
Operation
The class is proved as pylablib.devices.OZOptics.EPC04. It lets the user change the 4 control voltages, switch
between DC and AC (scrambling) modes, and change the AC frequency.
The class is proved as pylablib.devices.OZOptics.DD100. It simply lets the user query and change the attenuation,
as well as home the device. Note that homing is required once after the device power up, and it might in general sweep
over the whole range of attenuations.
The class is proved as pylablib.devices.OZOptics.TF100. It simply lets the user query and change the central
wavelength, as well as home the device. Note that homing is required once after the device power up, and it might in
general sweep over the whole range of wavelengths.
Note: Basic sensors communication concepts are described on the corresponding page
Elektro Automatik manufactures a range of lab power supplies. The code has been tested with PS-2000B series con-
troller (specifically, PS 2042-06B).
The main device class is pylablib.devices.ElektroAutomatik.PS2000B.
Software requirements
The devices provide a USB connection with a built-in USB-to-RS232 chip. They are automatically recognized as serial
ports by the operating system, and no additional software is required.
Connection
Since the devices are identified as COM ports, they use the standard connection method, and all you need to know is
their COM-port address (e.g., COM5):
Operation
The operation of this gauge is fairly straightforward, but there is a couple of points to keep in mind:
• The source can operate in the manual or in the remote mode. In the manual mode the device is controlled using
the front panel, but the values can still be read out. In the remote mode the outputs are controlled from the PC,
and the front panel controls are disabled. Upon creation one can specify the remote mode handling for the device:
either "manual" (it has to be enabled or disabled explicitly, and disabled by default) or "force" (remote mode
is enabled upon connection and disabled upon disconnection).
Voltcraft produces different basic measurement and electronic devices including multimeters, oscilloscopes, signal
generators, power supplies, and environment sensors.
Note: Basic sensors communication concepts are described on the corresponding page
There are different series of multimeters with somewhat different capabilities and fairly different communication meth-
ods and protocols. There are currently two different supported protocols. The firs has been designed with Voltcraft
VC-7055BT multimeter, but it might also be able to work with other 7000 series multimeters such as 7060 and 7200.
The second was designed with VC880, but might also work with VC650T.
The main device classes are pylablib.devices.Voltcraft.VC7055 and pylablib.devices.Voltcraft.
VC880.
Software requirements
VC7055 multimeters provides a bare RS232 interface, so any appropriate USB-to-RS232 adapter should work. VC880
multimeters show up as a standard HID device and are automatically supported by Windows.
Connection
VC7055 devices are identified as COM ports, so use the standard connection method, and all you need to know is their
COM-port address (e.g., COM5):
VC880 devices are identified either via their HID path (a fairly long and complicated string of symbols such as \\?
\hid#vid_10c4&pid_ea80#7&0000000&1&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}), and they can
be identified either using this string, or an integer index (Starting from 0) which selects one of the potentially suitable
devices in the system:
Operation
The operation of this multimeter is fairly straightforward, but there is a couple of points to keep in mind:
• The documentation from VC7055 multimeter does not always correctly reflect the communication protocol, and
the device behavior is sometimes strange (e.g., it return non-ASCII symbols or strange replies to commands).
The communication protocol is implemented as observed in reality, not as documented. Therefore, it is not
guaranteed, that the provided code will work with related models, such as other 7000-series multimeters, or even
with different revisions of the same model.
• Keep in mind that VC880 should be manually activated for PC communication by pressing PC button on the front
panel, and this needs to be done every time the device is turned on. Otherwise it is detected by the OS and can
be connected to, but it will not send updates or react to commands.
Note: Basic Modbus protocol concepts are described on the corresponding page
Lumel manufactures a range of automation electronics (sensors, relays, etc.), which frequently can be remotely con-
trolled using Modbus protocol. In addition to the generic Modbus control, pylablib implements RE72 temperature
controller in a bit more detail. The code has been tested with RE72-122200E0 controller and generic USB to RS485
converter.
The main device classes are pylablib.devices.Lumel.LumelRE72Controller.
Software requirements
Basic Lumel devices implement Modbus protocol over RS485 physical layer. If one uses a dedicated USB to RS485
controller or a USB to RS232 controller with RS232 to RS485 adapter, then it shows up as a serial port in the OS, and
no additional software is required.
Connection
Generally, you would need to know a serial port of the RS485 controller, the serial connection parameters (by default
it’s 9600 baud, 8 data bits, no parity bit, one stop bit) and the controller Modbus address (1 by default). For details, see
Modbus protocol description.
Operation
RE72
There are two sets of methods implemented. The first are the generic methods for getting and setting values of internal
registers: LumelRE72Controller.get_reg() and LumelRE72Controller.set_reg(). These allow full control
over the device. The description of the registers is given in the user’s manual (RS-485 INTERFACE section).
The second set of methods provides the basic temperature readout, as well as the setpoint control. These are imple-
mented in two varieties, floating point and integer, according to the two kinds of registers on the device. The integer
methods (ending with i, e.g., LumelRE72Controller.get_measurementi()) return integer value, whose interpre-
tation depends on the measurement units and other parameters (e.g., for temperature this is the value in 1/10th of the
current degree unit, C or F). The floating point methods return value in a more straightforward way (e.g., directly in
degrees), but they do not allow for setting of the temperature setpoint.
Note: Basic Modbus protocol concepts are described on the corresponding page
Omron manufactures a range of automation electronics (sensors, relays, controllers, etc.), which frequently can be
remotely controlled using Modbus protocol. In addition to the generic Modbus control, pylablib implements E5_C
(e.g., E5GC) temperature controller in a bit more detail. The code has been tested with E5GC-QX1A6M-015 controller
and generic USB to RS485 converter.
The main device classes are pylablib.devices.Omron.OmronE5xCController.
Software requirements
Basic Omron devices implement Modbus protocol over RS485 physical layer. If one uses a dedicated USB to RS485
controller or a USB to RS232 controller with RS232 to RS485 adapter, then it shows up as a serial port in the OS, and
no additional software is required.
Connection
Generally, you would need to know a serial port of the RS485 controller, the serial connection parameters (by default
it’s 9600 baud, 8 data bits, even parity bit, one stop bit) and the controller Modbus address (1 by default). For details,
see Modbus protocol description.
Operation
E5_C
There are two sets of methods implemented. The first are the generic methods for getting and setting values of internal
registers: OmronE5xCController.get_reg() and OmronE5xCController.set_reg(). These allow full control
over the device. The description of the registers is given in the controller communication manual (Communications
Data for Modbus section).
The second set of methods provides the basic temperature readout, as well as the setpoint control. Currently only
the most basic methods for getting the current temperature (OmronE5xCController.get_measurementi())
and controlling the setpoint (OmronE5xCController.get_setpointi() and OmronE5xCController.
set_setpointi()) are implemented
Note: General device communication concepts are described on the corresponding page.
There are several miscellaneous device classes, which are collected in this page. All of them implement straightforward
serial communication protocol, so the software requirements and the connection approach is the same for all of them.
Software requirements
All the devices provide either a bare RS232 interface, or a USB connection with a built-in USB-to-RS232 chip. In
either way, they are automatically recognized as serial ports, and no additional software is required.
Connection
The devices are identified as COM ports, so they use the standard connection method, and all you need to know is their
COM-port address (e.g., COM5):
Operation
There is some support for generic Windows drivers for some devices.
Joysticks
Basic support for Windows-compatible joysticks / gamepads using WinMM. Since the driver only supports polling, the
events (button/axis presses) are emulated using a separate polling loop. The main device class is pylablib.devices.
Windows.Joystick. Since this library is a standard part of Windows, no additional software is required, apart from
potential joystick drivers.
The code supports polling the joystick state (button and axes) as well as querying events:
Note: General device communication concepts are described on the corresponding page.
There exist generic mid-level communication protocols built on top of the existing communication channels. These are
not specific to any particular device, but simply provide a level of abstraction to implement specific devices later.
Modbus
This is one of the standard industrial communication protocols. It has several different implementations depending on
the underlying protocol (UART, TCP). Currently only Modbus RTU (binary protocol over UART) is supported.
The code is located in pylablib.devices.Modbus, and the main camera class is pylablib.devices.Modbus.
GenericModbusRTUDevice.
Software requirements
The requirements depend on the underlying transfer layer. Most common is the RS485 physical layer, where one
normally uses either a dedicated USB to RS485 controller, or a USB to RS232 controller with RS232 to RS485 adapter.
In this case, the RS485 controller shows up as a serial port in the OS, and no additional software is required.
Connection
To successfully communicate with a device, several pieces of information are needed. First, one needs to know the
serial port of the RS485 controller (e.g., "COM1" or "dev/ttyUSB0"). Next are the serial port parameters, such as
the baud rate, number of data bits, parity bits, and stop bits (the most common is 9600 baud with 8N1 format, i.e., 8
data bits, one parity bit, 1 stop bit). Finally, since several Modbus devices can be connected to the same controller, one
needs to know the specific device address, which is an integer between 1 and 247. Both the serial port parameters and
the device address are set at the device or specified in its documentation:
>> dev.close()
Note: Serial ports are exclusive OS resources, which means that only one instance of modbus.
GenericModbusRTUDevice can be opened at the same port, even if several devices are connected to the same RS485
controller. One can choose which device is addressed either by using daddr parameter in the methods, or by using
GenericModbusRTUDevice.mb_set_default_address() method.
Operation
The code implements the most basic Modbus methods for setting and reading coils, discrete inputs, and registers.
All relevant methods are prefixed with mb_, e.g., GenericModbusRTUDevice.mb_read_holding_registers()
or GenericModbusRTUDevice.mb_write_single_coil(). In addition, it implements a basic device scanning
method, which sends the same command to all possible addresses and notes which of them reply.
2.3.1 Fitting
Examples
Fitting a Lorentzian:
# fit_stderr is a dictionary containing the fit error for the corresponding parameters
fit_par, fit_func, fit_stderr = fitter.fit([xs,ys], img, return_stderr=True)
imshow(fit_func(xs, ys)) # plot fit result
There are several functions present for filtering the data to smooth it or reduce its size. Most of them are thin wrapper
around standard numpy or scipy method, but they provide more universal interface which work both with numpy arrays
and pandas DataFrames:
• First are the decimation functions: filters.decimate() (and its special case filters.
binning_average()), filters.decimate_full() and filters.decimate_datasets(). The first one
splits the supplied trace into consecutive segments of n points and compresses them into a single value using the
supplied method (e.g., "mean" will average them together, which is used for filters.binning_average()).
The second one completely decimates the dataset along the given axis (which is essentially identical to using
the standard numpy methods such as np.mean or np.max). The last one decimates several datasets together,
which is similar to combining them into a large (n+1)D array and fully decimating along the given axis:
array([0.75, 1.5 , 2.5 , 3.5 , 4.5 , 5.5 , 6.5 , 7.5 , 8.25, 8.5 ])
>> pll.sliding_filter(trace, 4, "max") # find maximum of points in 4-point window
array([2, 3, 4, 5, 6, 7, 8, 9, 9, 9])
• Next are convolution filters which operate by convolving the trace with a given kernel function. These involve
filters.gaussian_filter() (and filters.gaussian_filter_nd(), which is simply a wrapper around
scipy.ndimage.gaussian_filter()), and a more generic filters.convolution_filter(). Related are
infinite impulse response (IIR) filter filters.low_pass_filter() and filters.high_pass_filter(),
which mimic standard single-pole low-pass and high-pass filters. In principle, they can be modeled as a con-
volution with an exponential decay, but the implementation using the recursive filters is more efficient for large
widths.
• Finally, there are Fourier filters, which Fourier-transform the trace, scale the transform values, and trans-
form it back to the real domain. These involve the main function filters.fourier_filter(), which
takes a generic frequency response function, as well as two specific response function generators filters.
fourier_filter_bandpass() and filters.fourier_filter_bandstop(), both generating hard fre-
quency cutoff filters.
• In addition to “post-processing” filters described above, there are also “real-time” filters which serve to filter
data as it is acquired, e.g., to filter out temporary noise or spikes. There are two filters of this kind: filters.
RunningDecimationFilter and filters.RunningDebounceFilter. They are implemented as classes, and
both have methods to add a new datapoint, to get the current filter value, and to reset the filter.
There is a couple of methods to work with Fourier transform. They are built around numpy.fft.fft(), but allow
more convenient normalization (e.g., in units of power spectral density), and work better with pandas DataFrames.
They also have an option to automatically trim the trace length to the nearest “good” size, which is a product of small
primes. This can have fairly strong (up to a factor of several) effect on the transform runtime, while typically trimming
off less than 1% of the data.
The main methods are fourier.fourier_transform() for the direct transform, fourier.
inverse_fourier_transform() for the inverse transform, and fourier.power_spectral_density() for
the power spectral density:
1.005262206692361
>> np.mean(x**2)
1.005262206692361
Additionally, there is a variety of small functions to simplify some data analyses and transforms:
• Checking trace properties: dataproc.utils.is_ascending(), dataproc.utils.is_descending(),
dataproc.utils.is_ordered(), dataproc.utils.is_linear().
• Sorting by a given column: dataproc.utils.sort_by(); work both on pandas and numpy arrays
• Filtering: dataproc.utils.filter_by() and dataproc.utils.unique_slices() (a simple analog of
pandas pandas.DataFrame.groupby(), which works on numpy arrays)
• Binary search (both in ordered and unordered 1D arrays): dataproc.utils.find_closest_arg(),
dataproc.utils.find_closest_value(), and dataproc.utils.get_range_indices().
• Traces step analysis and unwrapping: dataproc.utils.find_discrete_step() tries to find a single number
which divides all values within a reasonable precision, and dataproc.utils.unwrap_mod_data() “unwraps”
modulo data (e.g., phase, which is defined mod 2pi) provided that the steps between two consecutive points are
less than 1/2 of the module.
• Cutting the trace to the given range, or cutting out a given range: dataproc.utils.cut_to_range() and
dataproc.utils.cut_out_regions().
• Converting between 2-column “XY” and complex representations: dataproc.utils.xy2c() and dataproc.
utils.c2xy()
• Scalar numerical utilities: utils.numerical.limit_to_range() (limit a value to lie in a given range, in-
cluding option for no limits in one or both directions), utils.numerical.gcd() and utils.numerical.
gcd_approx() (greatest common divisor or its approximate version for non-integer values)
Complex data storage in pylablib centers around 2 main components: the multi-level dictionary for representing hier-
archical data within the code, and file IO to (among other things) load and store it in a human-readable format.
dictionary.Dictionary is an expansion of the standard dict class which supports tree structures (nested dictionar-
ies). The extensions include:
• handling multi-level paths and nested dictionaries, with several different indexing methods
• iteration over the immediate branches, or over the whole tree structure
• some additional methods: mapping, filtering, finding difference between two dictionaries
• combined with pylablib.core.fileio allows to save and load the content in a human-readable format.
Creating and indexing:
>>> d = pll.Dictionary()
>>> d['d/0/x'] = 5
>>> d
Dictionary('d/0/x': 5)
>>> d['d/0/x'] # string path indexing
5
>>> d['d']['0']['x'] # nested indexing
5
>>> d['d','0','x'] # multi-level path indexing
5
>>> d['d',0,'x'] # all path elements are converted into strings
5
>>> d['d/0']['x'] # indexing styles can be freely mixed
5
>>> d['d','0/x']
5
>>> b = d['d'] # indexing a branch yields another Dictionary object
>>> b
Dictionary('0/x': 5)
>>> b['0/x'] = 10 # the branch shares the data with the main dictionary
>>> d
Dictionary('d/0/x': 10)
A dictionary can be build from a Python dict, which automatically normalizes paths and nested dictionaries:
Note: There are several limitations on the dictionary structure (mostly they involve possible paths and keys):
• As mentioned above, the keys are converted into strings to get the path; therefore, different Python object can
merge together (e.g., number 0 and string literal '0'). This also discourages use of some of the objects with
“underdefined” (implementation dependent) representations, for example, floating point numbers.
• Since the '/' symbol is used to split different path entries, it can’t be used inside a single-level key. It is possible
to re-define this symbol on dictionary creation; however, it might lead to compatibility issues.
• Empty keys are not allowed. When building a path, they are automatically dropped, so 'a/b', 'a/b/', 'a///
b//' all correspond to the same path.
• One path can either correspond to a branch node, or a leaf node. In other words, one path can’t be a prefix of
other paths and also contain data: structures like pll.Dictionary({ 'a':1, 'a/b':2}) are not allowed. To
get around this, one can define a specific “data key” not used anywhere else, and store data in a node under that
key (e.g., with the data key '#' the example before turns into a valid structure pll.Dictionary({ 'a/#':1,
'a/b/#':2})).
Thus, it is generally recommended to only use strings or non-negative integers as keys, and apply the same restrictions
to them as to the Python variable names (with the addition of names starting with a digit).
2.4.2 File IO
pylablib.core.fileio contains several function for saving and loading data into different kinds of files:
binary (loadfile.load_bin() and savefile.save_bin()), CSV (loadfile.load_csv() and savefile.
save_csv()), or dictionary (loadfile.load_dict() and savefile.save_dict()).
Binary files
The first (binary files) closely corresponds to numpy fromfile. In addition, it also allows automatic conversion into
pandas arrays, setting column names, and skipping some number of bytes from the start:
Furthermore, there is an option to save the binary data with a preamble dictionary file, which describes its structure
(columns, dtype, etc.) This way, one does not have specify these parameter in the loading code:
array([[0. , 0. ],
[1. , 0.33333333],
[2. , 1.33333333]])
Note that only homogeneous data (i.e., all columns having the same type) is currently supported. That’s why the first
column got converted from integers into reals.
CSV files
The functionality of the second one mimics pandas read_csv, but offers a bit more flexibility with more complicated
values in columns, such as tuples or binary strings:
C1 C2
0 0 (0, 0)
1 1 (1, 1)
2 2 (4, 8)
In addition, its default settings are a bit different: the column separator is a whitespace, the column names are contained
in the comment string (which removes occasional ambiguity), and the creation date string is appended by default.
Hence, the content of the file created above is
# C1 C2
0 (0, 0)
1 (1, 1)
2 (4, 8)
Note that currently it operates only with simple flat tables and does not support advanced pandas features such as index
or multi-index. If these are required, you can use savefile.save_csv_desc() and loadfile.load_csv_desc().
Similarly to savefile.save_bin_desc() and loadfile.load_bin_desc(), it saves a dictionary containing ad-
ditional description; however, the table is inlined by default, so only one file is generated:
C1 C2
10 0 (0, 0)
11 1 (1, 1)
12 2 (4, 8)
Dictionary files
Finally, dictionary saving and loading operates with dictionary objects. It is generally useful to load or save various
heterogeneous settings or parameters, such as device parameters, data processing parameters, and GUI or device state.
It supports most basic Python data types as values: standard scalar types (integers, reals, complex numbers, strings,
booleans, None), containers (tuples, lists, dictionaries, sets, including nested ones), binary and raw string representation
(e.g., b"\x00" or r"m\n\o"), short numpy arrays (represented as, e.g., "array([1, 2, 3])"), and inline tables
(which are interpreted as pandas table by default). The only common data type not included is named tuples; they get
automatically converted to regular tuples on saving.
The dictionary files have the key value line formats and typically use full paths (as opposed to, say, XML hierarchy),
which makes them easier to inspect and parse without pylablib. For example, the dictionary from the previous section
will be saved as
b/i 2
c/i 3
c/ii 4
d/0/x 5
a 1
Dictionary('plot/label': $\nu_0$
'plot/position': [(0, 0), (1, 1), (2, 3)]
'process/default/amplitude': 5.0
'process/default/frequency': (10+2j)
'process/points': [1. 2. 3.])
The format also supports hierarchy using //branch to mark a start of sub-branch and /// to mark its end. For example,
the dictionary above can be also saved as
//process
# indentation is not required, but helps to see the structure
points array([1., 2., 3.])
default/frequency 10+2.j
default/amplitude 5.
///
//plot
position [(0,0), (1,1), (2,3)]
label r"$\nu_0$"
///
Finally, it is possible to specify inline tables using special comment lines. For example,
# The key without the value marks the path to the table within the dictionary
data/table
## Begin table
1 1.j
2 4.j
3 9.j
## End table
Dictionary('data/table':
0 1
0 1 0.000000+1.000000j
1 2 0.000000+4.000000j
2 3 0.000000+9.000000j )
There is a number of methods which are minor expansions of the built-in file utilities:
• Accessing and changing file times: utils.files.get_file_creation_time(), utils.files.
get_file_modification_time(), utils.files.touch() (update the modification date).
• Generating new file names (e.g., for storing a new dataset): utils.files.generate_indexed_filename()
and utils.files.generate_prefixed_filename().
• Some path analysis methods: utils.files.fullsplit(), utils.files.normalize_path(), utils.
files.paths_equal(), utils.files.relative_path(); a lot of these have also been implemented in
pathlib module, and are kept for backwards compatibility.
• Checking if a string is a valid path: utils.files.is_path_valid().
• File copying and moving, which also creates containing folders if necessary: utils.files.copy_file(),
utils.files.move_file().
• Folder creation and cleaning: utils.files.ensure_dir(), utils.files.remove_dir(), utils.files.
remove_dir_if_empty(), utils.files.clean_dir().
2.5.2 Network
There is a simple wrapper class utils.net.ClientSocket, which simplifies some operations with the built-in
socket module. In addition, it also implements a couple of higher-level ways to send the data: either fixed length
(as in the usual socket), with the length prepended (in case the total length is initially unknown at the receiving end),
or using a delimiter to mark the end of the message.
In addition, there are several methods for gaining local or remote host information (utils.net.
get_local_addr(), utils.net.get_all_local_addr(), utils.net.get_local_hostname(), utils.
net.get_all_remote_addr(), utils.net.get_remote_hostname()), receiving JSON-formatted values
(utils.net.recv_JSON()), and listening on a given port (utils.net.listen()).
2.5.3 Strings
'[0, 1, 2, 3, 4]'
>> pll.from_string('[0, 1, 2, 3, 4]') # gets converted back into a list
[0, 1, 2, 3, 4]
>> pll.to_string(np.arange(5), use_classes=True) # use representation class
'array([0, 1, 2, 3, 4])'
>> pll.from_string('array([0, 1, 2, 3, 4])') # get converted back into an array
array([0, 1, 2, 3, 4])
More complex data classes can be added using utils.string.add_conversion_class() and utils.
string.add_namedtuple_class():
'(1, 2)'
>> pll.add_namedtuple_class(NamedTuple)
>> pll.to_string(nt, use_classes=True) # now the name marker is added
'NamedTuple(1, 2)'
>> pll.from_string('NamedTuple(1, 2)')
NamedTuple(field1=1, field2=2)
>> DifferentNamedTuple = collections.namedtuple("DifferentNamedTuple", ["field1",
˓→"field2"])
'DifferentNamedTuple(1, 2)'
Furthermore, there is a couple of auxiliary string functions to parse more complicated situations:
utils.string.escape_string() and utils.string.unescape_string() for escaping and unescap-
ing string with potentially confusing or unprintable characters (e.g., quotation marks, spaces, new
lines); utils.string.from_string_partial(), utils.string.from_row_string(), utils.string.
extract_escaped_string() to determine and extract the first value in a string which potentially has several
values.
• Comparing and searching string: utils.string.string_equal() (compare string using different rules such
as case sensitivity), utils.string.find_list_string(), utils.string.find_dict_string() (find
string in a list or a dictionary using different comparison rules).
• Filtering strings: utils.string.get_string_filter(), utils.string.sfglob(), and utils.string.
sfregex(). Creates filter functions which may include or exclude certain string patterns; these filter functions
can be later used in, e.g., file-related methods such as utils.files.list_dir().
Simplifies dealing with operation timeouts: checking how much time is left (including options for infinite time-
out), checking if timeout is passed, resetting, etc.
• Script restarting via utils.general.restart() (thread-controller style applications can also use thread.
controller.restart_app() for a more managed restart).
• utils.general.StreamFileLogger, which can be set up to log all outputs into a stream (e.g., stdout):
With the code above, all output to stderr will be logged into logerr.txt to be analyzed later. It can also be
set with autoflush=True to automatically flush the printed text, which helps with identifying crushing bugs,
and it can be supplied with a lock to help separate printouts from different threads.
Transitioning from version 0.x to version 1.x saw lots of interface changes which break backward compatibility. The
previous version of the library can be either obtained on PyPi using pip install "pylablib<1", or by using legacy
module. Hence, instead of
1.4.3
• Devices
– Added multiple devices:
∗ Agilent XGS600 pressure gauge controller
∗ Hubner Cobolt lasers (tested with Cobolt MLD 06-01 laser)
∗ Omron E5_C temperature controllers (tested with E5GC-QX1A6M-015 controller)
∗ Thorlabs Kinesis Piezo controllers (tested with KPZ101)
– Extended device support:
∗ Multi-axis Trinamic TMCM controllers (tested with TMCM6110)
∗ Matisse Commander server support for Sirah Matisse lasers
1.4.2
• Devices
– Added multiple devices:
∗ Andor Shamrock spectrographs
∗ ElektorAutomatick PS2000B power supply
∗ Keithley 2110 multimeter
∗ Lumel RE72 temperature controller (via Modbus RTU protocol)
∗ M2 Solstis EMM (external mixing module)
∗ Mightex S-Series cameras
∗ Generic NKT lasers Interbus protocol support (tested with NKT SuperK with Select spectral filter)
∗ Generic Modbus RTU protocol
∗ PhysikInstrumente E-515 piezo controller
∗ Rigol DP1116A power supply
∗ SmarAct MCS2 stage controller
∗ Standa 8SMC5 motion controller
∗ Thorlabs PM160 power meter
∗ Voltcraft VC-7055BT multimeter
– Extended device support:
∗ Thorlabs Scientific Cameras (Zelux, Kiralux) color mode
∗ Thorlabs APT/Kinesis motor controllers
∗ Trinamic TMCM1110 homing
– Added HID device communication backend
– Switched some camera code to Cython to support higher frame rates.
– Multiple bug fixes and improved support of specific models:
∗ Selection of RTS cycling for Arduino boards (better support for newer boards such as Leonardo)
∗ Support for SiliconSoftware microEnable 5 (Basler microEnable 5 marathon)
∗ Improved Sirah Matisse tuning support for frequency tuning and stitched scans based on HighFinesse
wavemeters feedback.
1.4.1
• Devices
– Added Basler pylon-compatible cameras, BitFlow frame grabbers, AlliedVision Bonito cameras, Thorlabs
Elliptec stages, PI-E516 piezo controller, and Sirah Matisse laser.
– Minor additions to Cryocon temperature controller, Cryomagnetics LM510 level meters, and NI DAQmx
DAQs. Improved performance of PCO cameras at high frame rates.
– Multiple minor bug fixes and improved support of specific models.
• Added encoding argument to file loading.
• Improved color images support in image plotter, minor additions to trace plotter.
• Added real-time binning and debounce filters.
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
• General
– Minor speedups through calls caching.
– Changed muxcall signature to allow multiple special argument values.
• Devices
– Added Princeton Instruments cameras, IDS uEye cameras (as an option in uc480 cameras backend),
Thorlabs Kinesis piezo motor controllers (e.g., KIM101) and quadrature photo-detector controllers (e.g.,
KPA101).
– Added RS485 Arcus connection and a simple single-motor stage (DMX-J-SA).
– Improved reliability if errors are encountered upon connection.
– Multiple minor bug fixes and improved support of specific models.
• GUI
– Added widgets: menu dropdown button, scroll area container, area highlighter.
– Added querying element position and layout shape in layout widgets.
– Added more utilities methods: querying containing layout, querying top-level parent, deleting widget.
• Threading
– Added simple profiling through yappi.
1.2.1
• General
– Added restarting methods for regular and threaded applications.
• Threading
– Bugfixes in cameras and camera threads.
– Bugfixes in streaming.
1.2.0
• General
– Added timing context manager for simple code timing checks.
– Improved RPyC wrapper logging and reliability.
– Added Anaconda support.
– Added minor network and file functions.
• Devices
– Added Newport Picomotor 8742 motor controller, Toptica iBeam Smart laser, older version of Thorlabs
FW motorized filter wheel.
– Added camera frame output format (list or array).
– Added use_cavity option to M2 Solstis laser.
– Added method for auto-detecting associations between PhotonFocus cameras and frame grabbers.
– Updated some generic classes (DCAM cameras, Thorlabs TLCamera cameras).
– Updated SCPI failsafe operation, improved Thorlabs FW reliability.
– Fixed several minor bugs.
• GUI
– Rewritten GUI values handling to pass calls in a hierarchical manner. This makes the operation more
predictable and overloading the behavior a bit easier.
– Added out-of-range value action for combo boxes.
– Fixed ImagePlotter incompatibility with the newer pyqtgraph versions, added separate x and y axis line
cuts selection.
– Minor layout handling bugfixes.
• Threading
– Released advanced threading functionality: table/frame streaming, device threads, basic frame processing.
– Task thread additions: delayed batch job stopping, context manager for task loop pausing.
– Added argument-dependent call queue limit.
– Improved threading speed and stability.
1.1.0
• General
– Reorganized the core modules import structure: now __init__.py modules are mostly empty, and all the
necessary imports are either exposed directly in pylablib (e.g., pylablib.Fitter), or should be ac-
cessed directly by the module (e.g. pll.core.dataproc.fitting.Fitter). Intermediate access (e.g.,
pll.core.dataproc.Fitter) is no longer supported.
– File IO functions (e.g., read_csv) can now take file-like objects in addition to paths.
• Devices
– Added Silicon Software frame grabbers interface and rearranged PhotonFocus code to include both IMAQ
and SiliconSoftware frame grabbers.
– Fixed various compatibility bugs arising for specific versions of Python or dependency modules: Kinesis
error with specific pyft232 versions, some DLL-dependent devices errors with Python 3.8+, DLL types in
32-bit Python.
– Addressed issue with occasional uc480 acquisition restarts, fixed M2 communication report errors.
• GUI and threading
– Added container and layout management classes in addition to parameter tables for more consistent GUI
structure organization.
– Added pylablib.widgets module which combines all custom widgets for the ease of using in layout
managers or custom applications.
– Fixed support for PySide2 Qt5 backed.
– Renamed setupUi -> setup for all widgets, and changed the GUI setup organization for many of them
(the functioning stayed the same).
– Reorganized scheduling in QTaskThread to treat jobs, commands, and subscriptions more consistently.
– Added basic data stream management.
1.0.0
There have been too many alterations to list here comprehensively. Below is the list of the largest changes.
• General
– Removed built-in DataTable class (together with core.datatable subpackage) in favor of pandas.
– Renamed file IO functions: instead of generic load and save methods there are now more specific
loadfile.load_csv(), loadfile.load_dict(), etc.
– Removed some legacy modules which are not used in the rest of the library.
– Renamed or moved certain modules: core.utils.rpyc -> core.utils.rpyc_utils, core.fileio.
logfile -> core.fileio.table_stream, core.fileio.binio -> core.utils.binio , core.
devio.backend -> core.devio.backencd_comm, core.devio.untis -> core.utils.units, core.
dataproc.waveforms -> core.dataproc.utils
• Devices
– Some legacy devices have been removed, since without access to the hardware it is hard to maintain and
expand them. These include most of Agilent devices (33502A amplifier, N9310A microwave generator, HP
8712B and HP 8722D network analyzers, HP 8168F laser), Rigol DSA1030A spectrum analyzer, Tektronix
MDO3000 oscilloscope, Vaunix LabBrick generators, Zurich Instruments HF2 and UHF, Andor Shamrock
spectrographs (should be restored in future releases), NuPhoton NP2000 EDFA, PurePhotonics PPCL200
laser, Sirah Matisse laser (should be restored in future releases), Thorlabs PM100 power meter (should be
restored in future releases), Lakeshore 370 resistance bridge (should be restored in future releases), MKS
900-series pressure gauges, and some custom devices (Arduino and Olimex AVR boards and Janis-related
hardware).
– The main devices package has been moved from pylablib.aux_libs.devices (which now refers to the
legacy code) to pylablib.devices. Module organization has also changed slightly. To find the required
modules and device class names, see the devices list.
– Lots of devices’ interface has varied slightly, to make the interface more uniform and compatible between
different kinds of devices. The changes are usually fairly straightforward (e.g., move_to instead of move).
In many cases the interface was also expanded to include additional available methods.
– Several devices have been added, generalized, or restructured:
0.4.1
Interface changes
• Slightly changed representations of complex number in to-string conversions depending on the conversion rules
("python" vs "text").
Additions
• Devices
– Added Thorlabs K10CR1 rotational stage (legacy.aux_libs.devices.Thorlabs.K10CR1)
– Added Andor Shamrock spectrographs (legacy.aux_libs.devices.AndorShamrock)
– Expanded Agilent AWG class
– Added more 32bit dlls
– Added list_resources method to every backend class, which lists available connections for this
backend (not available for every backend; so far only works in legacy.core.devio.backed.
VisaDeviceBackend, legacy.core.devio.backed.SerialDeviceBackend, and legacy.core.
devio.backed.FT232BackendOpenError.
• GUI and threading
– Added legacy.aux_libs.gui.helpers.TableAccumulatorThread.preprocess_data method to
pre-process incoming data before adding it to the table
– Added update_only_on_visible argument to legacy.aux_libs.gui.widgets.trace_plotter.
TracePlotter.setupUi method, and legacy.aux_libs.gui.widgets.trace_plotter.
TracePlotter.get_required_channels method.
0.4.0
Interface changes
• Dictionary entries (legacy.core.fileio.dict_entry) system has been slightly redesigned: building en-
tries from stored objects has been moved from legacy.core.fileio.dict_entry.IDictionaryEntry.
build_entry class method to a dedicated function legacy.core.fileio.dict_entry.build_entry, and
entry classes have been added.
• legacy.aux_libs.gui.helpers.StreamFormerThread architecture changes, so that it can accumu-
lates several rows before adding them into the storage; this lead to replacement of legacy.aux_libs.
gui.helpers.StreamFormerThread.prepare_new_row method by legacy.aux_libs.gui.helpers.
StreamFormerThread.prepare_new_data.
Additions
• General
– Added pandas support in a bunch of places: loading/saving tables and dictionaries; data processing rou-
tines in legacy.core.dataproc; conversion of legacy.core.dataproc.datatable.DataTable and
legacy.core.utils.dictionary.Dictionary object to/from pandas dataframes.
– Expanded string conversion to support more explicit variable classes. For example, a numpy array
np.array([1,2,3]) can be converted into a string 'array([1, 2, 3])' instead of a more am-
biguous string '[1, 2, 3]' (which can also be a list). This behavior is controlled by a new argu-
ment use_classes in string conversion functions (such as legacy.core.utils.string.to_string
some/long/prefix/x 1
some/long/prefix/y 2
some/long/prefix/y 3
can be represented as
//some/long/prefix
x 1
y 2
z 3
///
The meaningful elements are //some/long/prefix line denoting that following elements have the given
prefix, and /// line denoting that the prefix block is done (indentation is only added for clarity).
– New dictionary entries: dict_entry.ExternalNumpyDictionaryEntry (external numpy array, can
have arbitrary number of dimensions) and dict_entry.ExpandedContainerDictionaryEntry (turns
lists, tuples and dicts into dictionary branches, so that their content can benefit from the automatic table
inlining, dictionary entry classes, etc.).
• Data processing
– legacy.core.dataproc.fitting.Fitter now takes default scale and limit as constructor arguments.
– legacy.core.dataproc.feature.multi_scale_peakdet has new norm_ratio argument.
– legacy.core.dataproc.image.get_region and legacy.core.dataproc.image.
get_region_sum take axis argument.
• Miscellaneous
– Functions introspection module now supports Python 3 - style functions, and added a new function legacy.
core.utils.functions.funcsig
– legacy.core.utils.general.StreamFileLogger supports multiple destination paths
– New network function legacy.core.utils.net.get_all_local_addr (return list of all local ad-
dresses on all interfaces) and legacy.core.utils.net.get_local_hostname
2.7 pylablib
Subpackages
pylablib.core package
Subpackages
pylablib.core.dataproc package
Submodules
pylablib.core.dataproc.callable module
class pylablib.core.dataproc.callable.ICallable
Bases: object
Fit function generalization.
Has a set of mandatory argument with no default values and a set of parameters with default values (there may
or may not be an explicit list of them).
All the arguments are passed explicitly by name. Passed value supersede default values. Extra arguments (not
used in the calculations) are ignored.
Assumed (but not enforced) to be immutable: changes after creation can break the behavior.
Implements (possibly; depends on subclasses) call namelist binding boosting: if the function is to be called
many times with the same parameter names list, one can first bind parameters list, and then call bound function
with the corresponding arguments. This way, callable(**p) should be equivalent to callable.bind(p.
keys())(*p.values()).
has_arg(arg_name)
Determine if the function has an argument arg_name (of all 3 categories)
filter_args_dict(args)
Filter argument names dictionary to leave only the arguments that are used
get_mandatory_args()
Return list of mandatory arguments (these are the ones without default values)
is_mandatory_arg(arg_name)
Check if the argument arg_name is mandatory
get_arg_default(arg_name)
Return default value of the argument arg_name.
Raise KeyError if the argument is not defined or ValueError if it has no default value.
bind(arg_names, **bound_params)
Bind function to a given parameters set, leaving arg_names as free parameters (in the given order)
class NamesBoundCall(func, names, bound_params)
Bases: object
bind_namelist(arg_names, **bound_params)
Bind namelist to boost subsequent calls.
Similar to bind(arg_names), but bound function doesn’t accept additional parameters and can be boosted.
class pylablib.core.dataproc.callable.MultiplexedCallable(func, multiplex_by,
join_method='stack')
Bases: ICallable
Multiplex a single callable based on a single parameter.
If the function is called with this parameter as an iterable, then the underlying callable will be called for each
value of the parameter separately, and the results will be joined into a single array (if return the values are scalar,
they’re joined in 1D array; otherwise, they’re joined using join_method).
Parameters
• func (callable) – Function to be parallelized.
• multiplex_by (str) – Name of the argument to be multiplexed by.
• join_method (str) – Method for combining individual results together if they’re non-
scalars. Can be either 'list' (combine the results in a single list), 'stack' (combine using
numpy.column_stack(), i.e., add dimension to the result), or 'concatenate' (concate-
nate the return values; the dimension of the result stays the same).
Multiplexing also makes use of call signatures for underlying function even if __call__ is used.
Note that this operation is slow, and should be used only for high-dimensional multiplexing; for 1D case it’s
much better to just use numpy arrays as arguments and rely on numpy parallelizing.
has_arg(arg_name)
Determine if the function has an argument arg_name (of all 3 categories)
get_mandatory_args()
Return list of mandatory arguments (these are the ones without default values)
get_arg_default(arg_name)
Return default value of the argument arg_name.
Raise KeyError if the argument is not defined or ValueError if it has no default value.
class NamesBoundCall(func, names, bound_params)
Bases: object
bind(arg_names, **bound_params)
Bind function to a given parameters set, leaving arg_names as free parameters (in the given order)
bind_namelist(arg_names, **bound_params)
Bind namelist to boost subsequent calls.
Similar to bind(arg_names), but bound function doesn’t accept additional parameters and can be boosted.
filter_args_dict(args)
Filter argument names dictionary to leave only the arguments that are used
is_mandatory_arg(arg_name)
Check if the argument arg_name is mandatory
class pylablib.core.dataproc.callable.JoinedCallable(funcs, join_method='stack')
Bases: ICallable
Join several callables sharing the same arguments list.
The results will be joined into a single array (if return the values are scalar, they’re joined in 1D array; otherwise,
they’re joined using join_method).
Parameters
• funcs ([callable]) – List of functions to be joined together.
• join_method (str) – Method for combining individual results together if they’re non-
scalars. Can be either 'list' (combine the results in a single list), 'stack' (combine using
numpy.column_stack(), i.e., add dimension to the result), or 'concatenate' (concate-
nate the return values; the dimension of the result stays the same).
has_arg(arg_name)
Determine if the function has an argument arg_name (of all 3 categories)
get_mandatory_args()
Return list of mandatory arguments (these are the ones without default values)
get_arg_default(arg_name)
Return default value of the argument arg_name.
Raise KeyError if the argument is not defined or ValueError if it has no default value.
class NamesBoundCall(func, names, bound_params)
Bases: object
bind(arg_names, **bound_params)
Bind function to a given parameters set, leaving arg_names as free parameters (in the given order)
bind_namelist(arg_names, **bound_params)
Bind namelist to boost subsequent calls.
Similar to bind(arg_names), but bound function doesn’t accept additional parameters and can be boosted.
filter_args_dict(args)
Filter argument names dictionary to leave only the arguments that are used
is_mandatory_arg(arg_name)
Check if the argument arg_name is mandatory
class pylablib.core.dataproc.callable.FunctionCallable(func, function_signature=None,
defaults=None, alias=None)
Bases: ICallable
Callable based on a function or a method.
Parameters
• func – Function to be wrapped.
• function_signature – A functions.FunctionSignature object supplying informa-
tion about function’s argument names and default values, if they’re different from what’s
extracted from its signature.
• defaults (dict) – A dictionary {name: value} of additional default parameters values.
Override the defaults from the signature. All default values must be pass-able to the function
as a parameter
• alias (dict) – A dictionary {alias: original} for renaming some of the original ar-
guments. Original argument names can’t be used if aliased (though, multi-aliasing can be
used explicitly, e.g., alias={'alias':'arg','arg':'arg'}). A name can be blocked
(its usage causes error) if it’s aliased to None (alias={'blocked_name':None}).
Optional non-named arguments in the form *args are not supported, since all the arguments are passed to the
function by keywords.
Optional named arguments in the form **kwargs are supported only if their default values are explicitly pro-
vided in defaults (otherwise it would be unclear whether argument should be added into **kwargs or ignored
altogether).
has_arg(arg_name)
Determine if the function has an argument arg_name (of all 3 categories)
get_mandatory_args()
Return list of mandatory arguments (these are the ones without default values)
get_arg_default(arg_name)
Return default value of the argument arg_name.
Raise KeyError if the argument is not defined or ValueError if it has no default value.
class NamesBoundCall(func, names, bound_params)
Bases: object
bind(arg_names, **bound_params)
Bind function to a given parameters set, leaving arg_names as free parameters (in the given order)
bind_namelist(arg_names, **bound_params)
Bind namelist to boost subsequent calls.
Similar to bind(arg_names), but bound function doesn’t accept additional parameters and can be boosted.
filter_args_dict(args)
Filter argument names dictionary to leave only the arguments that are used
is_mandatory_arg(arg_name)
Check if the argument arg_name is mandatory
class pylablib.core.dataproc.callable.MethodCallable(method, function_signature=None,
defaults=None, alias=None)
Bases: FunctionCallable
Similar to FunctionCallable, but accepts class method instead of a function.
The only addition is that now object’s attributes can also parameters to the function: all the parameters which
are not explicitly mentioned in the method signature are assumed to be object’s attributes.
The parameters are affected by alias, but NOT affected by defaults (since it’s impossible to ensure that all object’s
attributes are kept constant, and it’s impractical to reset them all to default values at every function call).
Parameters
• method – Method to be wrapped.
• function_signature – A functions.FunctionSignature object supplying informa-
tion about function’s argument names and default values, if they’re different from what’s
extracted from its signature. If it’s assumed that the first self argument is already excluded.
• defaults (dict) – A dictionary {name: value} of additional default parameters values.
Override the defaults from the signature. All default values must be pass-able to the function
as a parameter
• alias (dict) – A dictionary {alias: original} for renaming some of the original ar-
guments. Original argument names can’t be used if aliased (though, multi-aliasing can be
used explicitly, e.g., alias={'alias':'arg','arg':'arg'}). A name can be blocked
(its usage causes error) if it’s aliased to None (alias={'blocked_name':None}).
This callable is implemented largely to be used with TheoryCalculator class (currently deprecated).
has_arg(arg_name)
Determine if the function has an argument arg_name (of all 3 categories)
get_arg_default(arg_name)
Return default value of the argument arg_name.
Raise KeyError if the argument is not defined or ValueError if it has no default value.
class NamesBoundCall(func, names, bound_params)
Bases: object
bind(arg_names, **bound_params)
Bind function to a given parameters set, leaving arg_names as free parameters (in the given order)
bind_namelist(arg_names, **bound_params)
Bind namelist to boost subsequent calls.
Similar to bind(arg_names), but bound function doesn’t accept additional parameters and can be boosted.
filter_args_dict(args)
Filter argument names dictionary to leave only the arguments that are used
get_mandatory_args()
Return list of mandatory arguments (these are the ones without default values)
is_mandatory_arg(arg_name)
Check if the argument arg_name is mandatory
pylablib.core.dataproc.callable.to_callable(func)
Convert a function to an ICallable instance.
If it’s already ICallable, return unchanged. Otherwise, return FunctionCallable or MethodCallable de-
pending on whether it’s a function or a bound method.
pylablib.core.dataproc.ctransform_fallback module
pylablib.core.dataproc.feature module
width
pylablib.core.dataproc.feature.get_baseline_simple(trace, find_width=True)
Get the baseline of the 1D trace.
If find_width==True, calculate its width as well.
pylablib.core.dataproc.feature.subtract_baseline(trace)
Subtract baseline from the trace (make its background zero).
class pylablib.core.dataproc.feature.Peak(position=0.0, height=1.0, width=1.0, kernel='generic')
Bases: Peak
A trace peak.
kernel defines its shape (for, e.g., generation purposes).
height
kernel
position
width
pylablib.core.dataproc.feature.peaks_sum_func(peaks, peak_func='lorentzian')
Create a function representing sum of peaks.
peak_func determines default peak kernel (used if peak.kernel=="generic"). Kernel is either a name string
or a function taking 3 arguments (x, width, height).
pylablib.core.dataproc.feature.get_kernel(width, kernel_width=None, kernel='lorentzian')
Get a finite-sized kernel.
Return 1D array of length 2*kernel_width+1 containing the given kernel. By default,
kernel_width=int(width*3).
pylablib.core.dataproc.feature.get_peakdet_kernel(peak_width, background_width,
kernel_width=None, kernel='lorentzian')
Get a peak detection kernel.
Return 1D array of length 2*kernel_width+1 containing the kernel. The kernel is a sum of narrow positive
peak (with the width peak_width) and a broad negative peak (with the width background_width); both widths
are specified in datapoints (index). Each peak is normalized to have unit sum, i.e., the kernel has zero total sum.
By default, kernel_width=int(background_width*3).
pylablib.core.dataproc.feature.multi_scale_peakdet(trace, widths, background_ratio, kind='peak',
norm_ratio=None, kernel='lorentzian')
Detect multiple peak widths using get_peakdet_kernel() kernel.
Parameters
• trace – 1D data array.
• widths ([float]) – Array of possible peak widths.
• background_ratio (float) – ratio of the background_width to the peak_width in
get_peakdet_kernel().
• kind (str) – Peak kind. Can be 'peak' (positive direction) or 'dip' (negative direction).
• norm_ratio (float) – if not None, defines the width of the “normalization region” (in units
of the kernel width, same as for the background kernel); it is then used to calculate a local
trace variance to normalize the peaks magnitude.
• kernel – Peak matching kernel.
Returns
Filtered trace which shows peak ‘affinity’ at each point.
pylablib.core.dataproc.feature.find_local_extrema(wf , region_width=3, kind='max',
min_distance=None)
Find local extrema (minima or maxima) of 1D trace.
kind can be "min" or "max" and determines the kind of the extrema. Local minima (maxima) are defined
as points which are smaller (greater) than all other points in the region of width region_width around it. re-
gion_width is always round up to an odd integer. min_distance defines the minimal distance between the extrema
(region_width//2 by default). If there are several extrema within min_distance, their positions are averaged
together.
pylablib.core.dataproc.feature.latching_trigger(wf , threshold_on, threshold_off , init_state='undef',
result_kind='separate')
Determine indices of rise and fall trigger events with hysteresis (latching) thresholds.
Return either two arrays (rise_trig, fall_trig) containing trigger indices (if
result_kind=="separate"), or a single array of tuples [(dir,pos)], where dir is the trigger direc-
tion (+1 or -1) and pos is its index (if result_kind=="joined"). Triggers happen when a state switch from
‘high’ to ‘low’ (rising) or vice versa (falling). The state switches from ‘low’ to ‘high’ when the trace value
goes above threshold_on, and from ‘high’ to ‘low’ when the trace value goes below threshold_off. For a stable
hysteresis effect, threshold_on should be larger than threshold_off, which means that the trace values between
these two thresholds can not change the state. init_state specifies the initial state: "low", "high", or "undef"
(undefined state).
pylablib.core.dataproc.filters module
• axis (int) – axis along which to perform the decimation; can also be a tuple, in which case
the same decimation is performed sequentially along several axes.
• mode (str) – determines what to do with the last bin if it’s incomplete. Can be either 'drop'
(omit the last bin) or 'leave' (keep it).
pylablib.core.dataproc.filters.binning_average(a, width, axis=0, mode='drop')
Binning average filter.
Equivalent to decimate() with dec=='bin'.
pylablib.core.dataproc.filters.decimate_full(a, dec='skip', axis=0)
Completely decimate the data along a given axis.
Parameters
• a – data array.
• dec (str) – decimation method. Can be - 'skip' - just leave every n’th point while com-
pletely omitting everything else; - 'bin' or 'mean' - do a binning average; - 'sum' - sum
points; - 'min' - leave min point; - 'max' - leave max point; - 'median' - leave median
point (works as a median filter). - a function which takes two arguments (nD numpy array
and an axis) and compresses the array along the given axis
• axis (int) – axis along which to perform the decimation; can also be a tuple, in which case
the same decimation is performed along several axes.
pylablib.core.dataproc.filters.decimate_datasets(arrs, dec='mean')
Decimate datasets with the same shape element-wise (works only for 1D or 2D arrays).
Note that the index data is taken from the first array in the list.
dec has the same values and meaning as in decimate(). The format of the output (numpy or pandas, and the
name of columns in pandas DataFrame) is determined by the first array in the list.
pylablib.core.dataproc.filters.collect_into_bins(values, distance, preserve_order=False,
to_return='value')
Collect all values into bins separated at least by distance.
Return the extent of each bin. If preserve_order==False, values are sorted before splitting. If
to_return="value", the extent is given in values; if to_return="index", it is given in indices (only useful
if preserve_order=True, as otherwise the indices correspond to a sorted array). If distance is a tuple, then it
denotes the minimal and the maximal separation between consecutive elements; otherwise, it is a single number
denoting maximal absolute distance (i.e., it corresponds to a tuple (-distance,distance)).
pylablib.core.dataproc.filters.split_into_bins(values, max_span, max_size=None)
Split values into bins of the span at most max_span and number of elements at most max_size.
If max_size is None, it’s assumed to be infinite. Return array of indices for each bin. Values are sorted before
splitting.
pylablib.core.dataproc.filters.fourier_filter(trace, response, dt=1, preserve_real=True)
Apply filter to a trace in the frequency domain.
response is a (possibly) complex function with single 1D real numpy array as a frequency argument. dt specifies
time step between consecutive points. Note that in case of a multi-column data the filter is applied column-wise;
this is in contrast with the Fourier transform methods, which would assume the first column to be times.
If preserve_real==True, then the response for negative frequencies is automatically taken to be complex
conjugate of the response for positive frequencies (so that the real trace stays real).
pylablib.core.dataproc.filters.fourier_make_response_real(response)
Turn a frequency filter function into a real one (in the time domain).
Done by reflecting and complex conjugating positive frequency part to negative frequencies. response is a func-
tion with a single argument (frequency), return value is a modified function.
pylablib.core.dataproc.filters.fourier_filter_bandpass(pass_range_min, pass_range_max)
Generate a bandpass filter function (hard cutoff).
The function is symmetric, so that it corresponds to a real response in time domain.
pylablib.core.dataproc.filters.fourier_filter_bandstop(stop_range_min, stop_range_max)
Generate a bandstop filter function (hard cutoff).
The function is symmetric, so that it corresponds to a real response in time domain.
class pylablib.core.dataproc.filters.RunningDecimationFilter(n, mode='mean',
on_incomplete='none')
Bases: object
Running decimation filter.
Remembers last n samples and returns their averages, median, etc.
Parameters
• n – decimation length
• mode – decimation mode ("mean", "median", "min", or "max")
• on_incomplete – determines what to return while the filter window is not yet full; can be
"none" (default, return None), or "partial" (operate on the partial accumulated data)
get()
Get the filtered result
add(x)
Add a new sample
reset()
Reset the filter
class pylablib.core.dataproc.filters.RunningDebounceFilter(n, precision=None, initial=None)
Bases: object
Running debounce filter.
“Sticks” to the current value and only switches when a new value remains constant (withing a given precision)
for a given number of samples. Filters out temporary spikes and short changes, conceptually similar to a running
median filter.
Parameters
• n – length of the required constant period
• precision – comparison precision (None means that the values should be exactly equal)
• initial – initial value; None means that the first sample sets this value
get()
Get the filtered result
add(x)
Add a new sample
reset()
Reset the filter
pylablib.core.dataproc.fitting module
set_xarg_name(xarg_name)
Set names of x arguments.
Can be a string (single argument) or a list (arbitrary number of arguments, including zero).
use_xarg()
Return True if the function requires x arguments
set_fixed_parameters(fixed_parameters)
Change fixed parameters
update_fixed_parameters(fixed_parameters)
Update the dictionary of fixed parameters
del_fixed_parameters(fixed_parameters)
Remove fixed parameters
set_fit_parameters(fit_parameters)
Change fit parameters
update_fit_parameters(fit_parameters)
Update the dictionary of fit parameters
del_fit_parameters(fit_parameters)
Remove fit parameters
fit(x=None, y=0, fit_parameters=None, fixed_parameters=None, scale='default', limits='default',
weights=1.0, parscore=None, return_stderr=False, return_residual=False, **kwargs)
Fit the data.
Parameters
• x – x arguments. If the function has single x argument, x is an array-like object; otherwise,
x is a list of array-like objects (can be None if there are no x parameters).
• y – Target function values.
• fit_parameters (dict) – Adds to the default fit_parameters of the fitter (has priority on
duplicate entries).
• fixed_parameters (dict) – Adds to the default fixed_parameters of the fitter (has pri-
ority on duplicate entries).
• scale (dict) – Defines typical scale of fit parameters (used to normalize fit parameters
supplied of scipy.optimize.least_squares()). Note: for complex parameters scale
must also be a complex number, with re and im parts of the scale variable corresponding to
the scale of the re and im part. If value is "default", use the value supplied on the fitter
creation (by default, no specific scales).
• limits (dict) – Boundaries for the fit parameters (missing entries are assumed to be
unbound). Each boundary parameter is a tuple (lower, upper). lower or upper can
be None, numpy.nan or numpy.inf (with the appropriate sign), which implies no bounds
in the given direction. Note: for compound data types (such as lists) the entries are still
tuples of 2 elements, each of which is either None (no bound for any sub-element) or has
the same structure as the full parameter. Note: for complex parameters limits must also be
complex numbers (or None), with re and im parts of the limits variable corresponding to
the limits of the re and im part. If value is "default", use the value supplied on the fitter
creation (by default, no limits).
• bound_func: the fit function with all the parameters bound (i.e., it only requires x
parameters).
• stderr: a dictionary {name: error} of standard deviation for fit parameters to
the return parameters.
Always zero, added for better compatibility with fit().
• residual: either a full array of residuals func(x,**params)-y (if
return_residual=='full') or
a mean magnitude of the residuals mean(abs(func(x,**params)-y)**2) (if
return_residual==True or return_residual=='mean'). Always zero, added
for better compatibility with fit().
Return type
tuple
pylablib.core.dataproc.fitting.huge_error(x, factor=100.0)
pylablib.core.dataproc.fitting.get_best_fit(x, y, fits)
Select the best (lowest residual) fit result.
x and y are the argument and the value of the bound fit function. fits is the list of fit results (tuples returned by
Fitter.fit()).
pylablib.core.dataproc.fourier module
• single_sided (bool) – If True, only leave positive frequency side of the PSD.
• window (str) – FT window. Can be 'rectangle' (essentially, no window), 'hann' or
'hamming'.
• window_power_compensate (bool) – If True, the data is multiplied by a compensating
factor to preserve power in the spectrum.
• raw (bool) – if True, return a simple 1D trace with the result.
Returns
a two-column array, where the first column is frequency, and the second is positive PSD.
pylablib.core.dataproc.fourier.get_real_part_ft(ft)
Get the fourier transform of the real part only from the fourier transform of a complex variable.
pylablib.core.dataproc.fourier.get_imag_part_ft(ft)
Get the fourier transform of the imaginary part only from the fourier transform of a complex variable.
pylablib.core.dataproc.fourier.get_correlations_ft(ft_a, ft_b, zero_mean=True,
normalization='none')
Calculate the correlation function of the two variables given their fourier transforms.
Parameters
• ft_a – first variable fourier transform
• ft_b – second variable fourier transform
• zero_mean (bool) – If True, the value corresponding to the zero frequency is set to zero
(only fluctuations around means of a and b are calculated).
• normalization (str) – Can be 'whole' (correlations are normalized by product of
PSDs derived from ft_a and ft_b) or 'individual' (normalization is done for each fre-
quency individually, so that the absolute value is always 1).
pylablib.core.dataproc.iir_transform module
pylablib.core.dataproc.image module
center(shape=None)
size(shape=None)
area(shape=None)
tup(shape=None)
ispan(shape=None)
jspan(shape=None)
classmethod intersect(*args)
limit(shape)
pylablib.core.dataproc.interpolate module
pylablib.core.dataproc.specfunc module
pylablib.core.dataproc.specfunc.get_window_func(window)
Get a window function by its name.
Available functions are: 'hamming', 'rectangle', 'hann'.
pylablib.core.dataproc.specfunc.gen_hamming_w_ft(f , t, alpha, beta)
Get Fourier Transform of a generalized Hamming FT window function.
f is the argument, t is the total window size.
pylablib.core.dataproc.specfunc.rectangle_w_ft(f , t)
Get Fourier Transform of the rectangle FT window function.
f is the argument, t is the total window size.
pylablib.core.dataproc.specfunc.hann_w_ft(f , t)
Get Fourier Transform of the Hann FT window function.
f is the argument, t is the total window size.
pylablib.core.dataproc.specfunc.hamming_w_ft(f , t)
Get Fourier Transform of the specific Hamming FT window function.
f is the argument, t is the total window size.
pylablib.core.dataproc.specfunc.get_window_ft_func(window)
Get a Fourier Transform of a window function by its name.
Available functions are: 'hamming', 'rectangle', 'hann'.
pylablib.core.dataproc.table_wrap module
Utilities for uniform treatment of pandas tables and numpy arrays for functions which can deal with them both.
class pylablib.core.dataproc.table_wrap.IGenWrapper(container)
Bases: object
The interface for a wrapper that gives a uniform access to basic methods of wrapped objects’.
get_type()
Get a string representing the wrapped object type
copy(wrapped=False)
Copy the object.
If wrapped==True, return a new wrapper containing the object copy; otherwise, just return the copy.
ndim()
shape()
class pylablib.core.dataproc.table_wrap.I1DWrapper(container)
Bases: IGenWrapper
A wrapper containing a 1D object (a 1D numpy array or a pandas Series object).
Provides a uniform access to basic methods of a wrapped object.
class Accessor(wrapper)
Bases: object
An accessor: creates a simple uniform interface to treat the wrapped object element-wise (get/set/iterate
over elements).
Generated automatically for each table on creation, doesn’t need to be created explicitly.
subcolumn(idx, wrapped=False)
Return a subcolumn at index idx.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
static from_array(array, index=None, force_copy=False, wrapped=False)
Build a new object of the type corresponding to the wrapper from the supplied array (a 1D numpy array
or a list).
If force_copy==True, make a copy of supplied array. If wrapped==True, return a new wrapper con-
taining the column; otherwise, just return the column.
classmethod from_columns(columns, column_names=None, index=None, wrapped=False)
Build a new object of the type corresponding to the wrapper from the supplied columns (a list of columns;
only length-1 lists is supported).
column_names parameter is ignored. If wrapped==True, return a new wrapper containing the column;
otherwise, just return the column.
array_replaced(array, force_copy=False, preserve_index=False, wrapped=False)
Return a copy of the column with the data replaced by array.
All of the parameters are the same as in from_array().
get_index()
Get index of the given 1D trace, or None if none is available
get_type()
Get a string representing the wrapped object type
copy(wrapped=False)
Copy the object.
If wrapped==True, return a new wrapper containing the object copy; otherwise, just return the copy.
ndim()
shape()
class pylablib.core.dataproc.table_wrap.Array1DWrapper(container)
Bases: I1DWrapper
A wrapper for a 1D numpy array.
Provides a uniform access to basic methods of a wrapped object.
get_deleted(idx, wrapped=False)
Return a copy of the column with the data at index idx deleted.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
shape()
class pylablib.core.dataproc.table_wrap.Series1DWrapper(container)
Bases: I1DWrapper
A wrapper for a pandas Series object.
Provides a uniform access to basic methods of a wrapped object.
get_deleted(idx, wrapped=False)
Return a copy of the column with the data at index idx deleted.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
get_inserted(idx, val, wrapped=False)
Return a copy of the column with the data val added at index idx.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
get_appended(val, wrapped=False)
Return a copy of the column with the data val appended at the end.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
subcolumn(idx, wrapped=False)
Return a subcolumn at index idx.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
static from_array(array, index=None, force_copy=False, wrapped=False)
Build a new object of the type corresponding to the wrapper from the supplied array (a 1D numpy array
or a list).
If force_copy==True, make a copy of supplied array. If wrapped==True, return a new wrapper con-
taining the column; otherwise, just return the column.
get_index()
Get index of the given 1D trace, or None if none is available
get_type()
Get a string representing the wrapped object type
copy(wrapped=False)
Copy the object.
If wrapped==True, return a new wrapper containing the object copy; otherwise, just return the copy.
class Accessor(wrapper)
Bases: object
An accessor: creates a simple uniform interface to treat the wrapped object element-wise (get/set/iterate
over elements).
Generated automatically for each table on creation, doesn’t need to be created explicitly.
array_replaced(array, force_copy=False, preserve_index=False, wrapped=False)
Return a copy of the column with the data replaced by array.
All of the parameters are the same as in from_array().
shape()
ndim()
shape()
class pylablib.core.dataproc.table_wrap.Array2DWrapper(container)
Bases: I2DWrapper
A wrapper for a 2D numpy array.
Provides a uniform access to basic methods of a wrapped object.
set_container(cont)
get_appended(val, wrapped=False)
Return a new table with new columns given by val appended to the end of the table.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
append(val)
Insert new columns given by val to the end of the table
set_names(names)
Set column names (does nothing)
get_names()
Get column names (all names are None)
get_column_index(idx)
Get number index for a given column index
class TableAccessor(storage)
Bases: object
A table accessor: accessing the table data through this interface returns an object of the appropriate type
(numpy array for numpy wrapped object, and a DataFrame for a pandas DataFrame wrapped object).
Generated automatically for each table on creation, doesn’t need to be created explicitly.
subtable(idx, wrapped=False)
Return a subtable at index idx of the appropriate type (2D numpy array).
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
column(idx, wrapped=False)
Get a column at index idx as a 1D numpy array.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
classmethod from_columns(columns, column_names=None, index=None, wrapped=False)
Build a new object of the type corresponding to the wrapper from the supplied columns (a list of columns).
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table. col-
umn_names parameter is ignored.
static from_array(array, column_names=None, index=None, force_copy=False, wrapped=False)
Build a new object of the type corresponding to the wrapper from the supplied array (a list of rows or a
2D numpy array).
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table. col-
umn_names parameter is ignored.
get_type()
Get a string representing the wrapped object type
copy(wrapped=False)
Copy the object.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
array_replaced(array, preserve_index=None, force_copy=False, wrapped=False)
Return a copy of the column with the data replaced by array.
All of the parameters are the same as in from_array().
shape()
class pylablib.core.dataproc.table_wrap.DataFrame2DWrapper(container)
Bases: I2DWrapper
A wrapper for a pandas DataFrame object.
Provides a uniform access to basic methods of a wrapped object.
class RowAccessor(wrapper, storage)
Bases: object
A row accessor: creates a simple uniform interface to treat the wrapped object row-wise (ap-
pend/insert/delete/iterate over rows).
Generated automatically for each table on creation, doesn’t need to be created explicitly.
get_deleted(idx, wrapped=False)
Return a copy of the column with the data at index idx deleted.
If wrapped==True, return a new wrapper containing the column; otherwise, just return the column.
get_inserted(idx, val, wrapped=False)
Return a new table with new rows given by val inserted at idx.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
insert(idx, val)
Insert new rows given by val at index idx.
get_appended(val, wrapped=False)
Return a new table with new rows given by val appended to the end of the table.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
append(val)
Insert new rows given by val to the end of the table
class ColumnAccessor(wrapper, storage)
Bases: object
A column accessor: creates a simple uniform interface to treat the wrapped object column-wise (ap-
pend/insert/delete/iterate over columns).
Generated automatically for each table on creation, doesn’t need to be created explicitly.
get_deleted(idx, wrapped=False)
Return a new table with the columns at idx deleted.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
copy(wrapped=False)
Copy the object. If wrapped==True, return a new wrapper containing the table; otherwise, just return the
table
array_replaced(array, preserve_index=None, force_copy=False, wrapped=False)
Return a copy of the column with the data replaced by array.
All of the parameters are the same as in from_array().
columns_replaced(columns, preserve_index=False, wrapped=False)
Return copy of the object with the data replaced by columns.
If wrapped==True, return a new wrapper containing the table; otherwise, just return the table.
ndim()
shape()
pylablib.core.dataproc.table_wrap.wrap1d(container)
Wrap a 1D container (a 1D numpy array or or a pandas Series) into an appropriate wrapper
pylablib.core.dataproc.table_wrap.wrap2d(container)
Wrap a 2D container (a 2D numpy array or a pandas DataFrame) into an appropriate wrapper
pylablib.core.dataproc.table_wrap.wrap(container)
Wrap container (a numpy array, a pandas Series or a pandas DataFrame) into an appropriate wrapper
pylablib.core.dataproc.transform module
inverted()
Return inverted transformation
preceded(trans)
Return a combined transformation which result from applying this transformation followed by trans
followed(trans)
Return a combined transformation which result from applying trans followed by this transformation
shifted(shift, preceded=False)
Return a transform with an added shift before or after (depending of preceded) the current one
multiplied(mult, preceded=False)
Return a transform with an added scaling before or after (depending of preceded) the current one.
mult can be a single number (scale), a 1D vector (scaling for each axis independently), or a matrix.
rotated2d(deg, preceded=False)
Return a transform with an added rotation before or after (depending of preceded) the current one.
Only applies to 2D transforms.
class pylablib.core.dataproc.transform.Indexed2DTransform(tmatr=None, shift=None, rigid=False)
Bases: LinearTransform
A restriction of LinearTransform which only applies to 2D and only allows rotations by multiples of 90 de-
grees.
Parameters
• tmatr – translational matrix (if None, use a unity matrix)
• shift – added shift (if None, use a zero shift)
• rigid – if True, only allow orthogonal transforms, i.e., no scaling
rotated2d(deg, preceded=False)
Return a transform with an added rotation before or after (depending of preceded) the current one.
Only applies to 2D transforms.
followed(trans)
Return a combined transformation which result from applying trans followed by this transformation
i(coord, shift=True)
inverted()
Return inverted transformation
multiplied(mult, preceded=False)
Return a transform with an added scaling before or after (depending of preceded) the current one.
mult can be a single number (scale), a 1D vector (scaling for each axis independently), or a matrix.
preceded(trans)
Return a combined transformation which result from applying this transformation followed by trans
shifted(shift, preceded=False)
Return a transform with an added shift before or after (depending of preceded) the current one
pylablib.core.dataproc.utils module
pylablib.core.dataproc.utils.is_ordered(trace)
Check if the trace is ordered (ascending or descending).
If it has more than 1 dimension, check all lines along 0’th axis.
pylablib.core.dataproc.utils.is_linear(trace)
Check if the trace is linear (values go with a constant step).
If it has more than 1 dimension, check all lines along 0’th axis (with the same step for all).
pylablib.core.dataproc.utils.get_x_column(t, x_column=None, idx_default=False)
Get x column of the table.
x_column can be
• an array: return as is;
• '#': return index array;
• None: equivalent to ‘#’ for 1D data if idx_default==False, or to 0 otherwise;
• integer: return the column with this index.
pylablib.core.dataproc.utils.get_y_column(t, y_column=None)
Get y column of the table.
y_column can be
• an array: return as is;
• '#': return index array;
• None: return t for 1D data, or the column 1 otherwise;
• integer: return the column with this index.
pylablib.core.dataproc.utils.sort_by(t, x_column=None, reverse=False, stable=False)
Sort a table using selected column as a key and preserving rows.
If reverse==True, sort in descending order. x_column values are described in get_x_column(). If
stable==True, use stable sort (could be slower and uses more memory, but preserves the order of elements
for the same key)
pylablib.core.dataproc.utils.filter_by(t, columns=None, pred=None, exclude=False)
Filter 1D or 2D array using a predicate.
If the data is 2D, columns contains indices of columns to be passed to the pred function. If exclude==False,
drop all of the rows satisfying pred rather than keep them.
pylablib.core.dataproc.utils.unique_slices(t, u_column)
Split a table into subtables with different values in a given column.
Return a list of t subtables, each of which has a different (and equal among all rows in the subtable) value in
u_column.
pylablib.core.dataproc.utils.merge(ts, idx=None, as_array=True)
Merge several tables column-wise.
If idx is not None, then it is a list of index columns (one column per table) used for merging. The rows that have
the same value in the index columns are merged; if some values aren’t contained in all the ts, the corresponding
rows are omitted. If idx is None, just join the tables together (they must have the same number of rows).
If as_array==True, return a simple numpy array as a result; otherwise, return a pandas DataFrame if applicable
(note that in this case all column names in all tables must be different to avoid conflicts)
property stop
contains(x)
Check if x is in the range
intersect(*rngs)
Find an intersection of multiple ranges.
If the intersection is empty, return None.
rescale(mult=1.0, shift=0.0)
tup()
Module contents
pylablib.core.devio package
Submodules
pylablib.core.devio.SCPI module
Bases: ICommBackendWrapper
A base class for a device controlled with the usual SCPI syntax.
Implements two functions:
• deals with composing and parsing of standard SCPI commands and simplifying repetitive property
access routines
• implements automatic re-sending and reconnecting on communication failures (fail-safe mode)
Parameters
• conn – Connection parameters (depend on the backend). Can also be an opened
comm_backend.IDeviceCommBackend class for a custom backend.
• term_write (str) – Line terminator for writing operations.
• wait_callback (callable) – A function to be called periodically (every 300ms by
default) while waiting for operations to complete.
• backend (str) – Connection backend (e.g., 'serial' or 'visa').
• backend_defaults – if not None, specifies a dictionary {backend: params} with
default connection parameters (depending on the backend), which are added to conn
• failsafe (bool) – If True, the device is working in a fail-safe mode: if an operation
times out, attempt to repeat it several times before raising error. If None, use the class
value _default_failsafe (False by default).
• timeout (float) – Default timeout (in seconds).
Error
alias of DeviceError
ReraiseError = None
BackendError
alias of DeviceBackendError
reconnect(new_instrument=True, ignore_error=True)
Remake the connection.
If new_instrument==True, create a new backend instance. If ignore_error==True, ignore errors on
closing.
sleep(delay)
Wait for delay seconds
using_write_buffer()
Context manager for using a write buffer.
While it’s active, all the consecutive write() operations are bundled together with ; delimiter. The actual
write is performed at the read()/ask() operation or at the end of the block.
get_id(timeout=None)
Get the device IDN. (query SCPI '*IDN?' command)
reset()
Reset the device (by default, "*RST" command)
get_esr(timeout=None)
Get the device status register (by default, "*ESR?" command)
wait_sync(timeout=None, wait_callback=None)
Pause execution of the script until device overlapped commands (e.g., taking sweeps) are complete.
timeout and wait_callback override default constructor parameters.
wait_dev()
Pause execution of the device commands until device overlapped commands (e.g., taking sweeps) are
complete.
Note that the code execution is not paused.
wait(wait_type='sync', timeout=None, wait_callback=None)
Pause execution until device overlapped commands are complete.
wait_type is either 'sync' (perform wait_sync()), 'dev' (perform wait_dev()) or 'none' (do noth-
ing).
static get_arg_type(arg)
Autodetect argument type
write(msg, arg=None, arg_type=None, unit=None, bool_selector=None, wait_sync=None,
read_echo=False, read_echo_delay=0.0)
Send a command.
Parameters
• msg (str) – Text message.
• arg – Optional argument to append in the end. If a list of arguments is supplied, the
result is joined with ",".
• arg_type (str) – Argument type. Can be 'raw' (in which case data is sent raw),
'string', 'int', 'float', 'bool', a format string (such as '{:.3f}') or a list of
argument types (for an iterable argument); if format string is used and the argument is
a list or a tuple, then it is expanded as a list of arguments (e.g., arg_type='{0};{1}'
with arg=[1,2] will produce a string '1;2'); if a list of types is used, each element
of arg is converted using the corresponding type, and the result is joined with ",".
• unit (str) – If not None, use it as a unit to append after the value.
• bool_selector (tuple) – A tuple (false_value, true_value) of two strings
to represent bool argument; by default, use ._bool_selector attribute.
• wait_sync – if True, append the sync command (specified as ._wait_sync_comm
attribute, "*OPC?" by default) after the message and pause the execution com-
mand is complete; useful in long set operations, where the device might ignore
later inputs until the current command is complete; if None, use the class default .
_default_write_sync attribute (False by default).
• read_echo (bool) – If True, read a single line after write.
• read_echo_delay (float) – The delay between write and read if
read_echo==True.
read(data_type='string', timeout=None)
Read data from the device.
data_type determines the type of the data. Can be 'raw' (just raw data), 'string' (with trailing and
leading spaces stripped), 'int', 'float', 'bool' (interprets 0 or 'off' as False, anything else as
True), 'value' (returns tuple (value, unit), where value is float), a callable (return the result of this
callable applied to the string value), a dictionary (return the stored value corresponding to the string value,
or to the value converted into integer if the string value is not present), or a list of data types (the result is
treated as a list of values with the given types separated by commas). timeout overrides the default value.
class NoParameterCaller(device, kind)
Bases: object
Class to simplify calling functions without a parameter
ask(msg, data_type='string', delay=0.0, timeout=None, read_echo=False)
Write a message and read a reply.
msg is the query message, delay is the delay between write and read. Other parameters are the same as in
read(). If read_echo==True, assume that the device first echoes the input and skip it.
close()
Close the backend
get_device_variable(key)
Get the value of a settings, status, or full info parameter
get_full_info(include=0)
Get dict {name: value} containing full device information (including status and settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_full_status(include=0)
Get dict {name: value} containing the device status (including settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_settings(include=0)
Get dict {name: value} containing all the device settings.
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
is_opened()
Check if the device is connected
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
open()
Open the backend
set_device_variable(key, value)
Set the value of a settings parameter
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
flush(one_line=False)
Flush the read buffer (read all the available data and return the number of bytes read).
If one_line==True, read only a single line.
read_binary_array_data(include_header=False, timeout=None, flush_term=True)
Read a binary data in the from the device.
The data assumes the standard binary transfer header consisting of "#" symbol, then a single digit with
the size of the length string, then the length string containing the length of the binary data (in bytes).
If include_header==True, return the data with the header; otherwise, return only the content. If
flush_term==True, flush the following line to skip terminator characters after the binary data, which
are added by some devices. timeout overrides the default value.
static parse_array_data(data, fmt, include_header=False)
Parse the data returned by the device. fmt is DataFormat description in numpy format (e.g., "<u2").
If include_header==True, the data is assumed to be in a (somewhat) standard SCPI format: b'#',
then a single digit s denoting length of the size block, then s digits denoting length of the data (in bytes)
followed by the actual data. Otherwise (include_header==False), assume that the header is already
removed.
apply_settings(settings)
Apply the settings.
settings is a dict {name: value} of the available device settings. Non-applicable settings are ignored.
pylablib.core.devio.backend_logger module
class pylablib.core.devio.backend_logger.BackendLogger(path)
Bases: object
Backend logger.
Receives log requests from backends and stores them in a predefined file.
Parameters
path – path to save the log
start(header)
Start logging section
stop()
Stop logging section
section(header)
Context manager for operations within a header
log(operation, value)
Log the operation
pylablib.core.devio.backend_logger.load_logfile(path)
Load backend log file.
Return a list of tuples [(header, section)], where header is the header name, and section is the list [(op,
value)] with operations ("r", "w", or "e") nd corresponding values.
pylablib.core.devio.base module
exception pylablib.core.devio.base.DeviceError
Bases: RuntimeError
Generic device communication error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
pylablib.core.devio.comm_backend module
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
pylablib.core.devio.comm_backend.reraise(func)
Wrapper for a backend method which intercepts backend exceptions and re-emits them as a subclass of
DeviceBackendError defined in the class
pylablib.core.devio.comm_backend.logerror(func)
Wrapper for a backend method which logs if any errors escaped
class pylablib.core.devio.comm_backend.IDeviceCommBackend(conn, timeout=None, term_write=None,
term_read=None, datatype='auto',
reraise_error=None)
Bases: object
An abstract class for a device communication backend.
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters (depend on the backend).
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations.
• term_read (str) – Line terminator for reading operations.
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object),
"str" (return str object), or "auto" (default Python result: str in Python 2 and bytes
in Python 3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError = None
Base class for the errors raised by the backend operations
Error
alias of DeviceBackendError
classmethod combine_conn(conn1, conn2)
Combined two connection parameters into a single dictionary (conn1 overrides conn2)
classmethod get_backend_name()
Get string representation of the backend (e.g., "serial", "visa", or "network")
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
cooldown(kind='default')
Cooldown between the operations.
kind specifies the operation kind (common kinds are open, close, read, write, timeout, and flush);
"default" corresponds to the default cooldown (usually, specified as 0). Called automatically by various
backend operations, so usually there is no need to call explicitly.
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
readline(remove_term=True, timeout=None, skip_empty=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• skip_empty (bool) – If True, ignore empty lines (works only for
remove_term==True).
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
read(size=None)
Read data from the device.
If size is not None, read size bytes (the standard timeout applies); otherwise, read all available data (return
immediately).
flush_read()
Flush the device output (read all the available data; return the number of bytes read)
write(data, flush=True, read_echo=False, read_echo_delay=0, read_echo_lines=1)
Write data to the device.
If flush==True, flush the write buffer. If read_echo==True, wait for read_echo_delay seconds and
then perform readline() (read_echo_lines times).
ask(query, delay=0.0, read_all=False)
Perform a write followed by a read, with delay in between.
If read_all==True, read all the available data; otherwise, read a single line.
static list_resources(desc=False)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
pylablib.core.devio.comm_backend.remove_longest_term(msg, terms)
Remove the longest terminator among terms from the end of the message.
exception pylablib.core.devio.comm_backend.DeviceVisaError(exc)
Bases: DeviceBackendError
Visa backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.VisaDeviceBackend(conn, timeout=10.0, term_write=None,
term_read=None, do_lock=None,
datatype='auto', reraise_error=None)
Bases: IDeviceCommBackend
NIVisa backend (via pyVISA).
Connection is automatically opened on creation.
Parameters
• conn (str) – Connection string.
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations; appended to the data
• term_read (str) – Line terminator for reading operations (specifies when readline()
stops).
• do_lock (bool) – If True, employ locking operations; otherwise, locking function does
nothing.
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError
Base class for the errors raised by the backend operations
alias of object
Error
alias of DeviceVisaError
static list_resources(desc=False)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
lock(timeout=None)
Lock the access to the device from other threads/processes
unlock()
Unlock the access to the device from other threads/processes
locking(timeout=None)
Context manager for lock & unlock
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
readline(remove_term=True, timeout=None, skip_empty=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• skip_empty (bool) – If True, ignore empty lines (works only for
remove_term==True).
read(size=None)
Read data from the device.
If size is not None, read size bytes (the standard timeout applies); otherwise, read all available data (return
immediately).
write(data, flush=True, read_echo=False, read_echo_delay=0, read_echo_lines=1)
Write data to the device.
If read_echo==True, wait for read_echo_delay seconds and then perform readline() (read_echo_lines
times). flush parameter is ignored.
ask(query, delay=0.0, read_all=False)
Perform a write followed by a read, with delay in between.
If read_all==True, read all the available data; otherwise, read a single line.
classmethod combine_conn(conn1, conn2)
Combined two connection parameters into a single dictionary (conn1 overrides conn2)
cooldown(kind='default')
Cooldown between the operations.
kind specifies the operation kind (common kinds are open, close, read, write, timeout, and flush);
"default" corresponds to the default cooldown (usually, specified as 0). Called automatically by various
backend operations, so usually there is no need to call explicitly.
flush_read()
Flush the device output (read all the available data; return the number of bytes read)
classmethod get_backend_name()
Get string representation of the backend (e.g., "serial", "visa", or "network")
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceSerialError(exc)
Bases: DeviceBackendError
Serial backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.SerialDeviceBackend(conn, timeout=10.0, term_write=None,
term_read=None,
connect_on_operation=False,
open_retry_times=3, no_dtrrts=False,
datatype='auto', reraise_error=None)
Bases: IDeviceCommBackend
Serial backend (via pySerial).
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters. Can be either a string (for a port), or a list/tuple (port,
baudrate, bytesize, parity, stopbits, xonxoff, rtscts, dsrdtr) sup-
plied to the serial connection (default is ('COM1',19200,8,'N',1,0,0,0)), or a dict
with the same parameters.
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations; appended to the data
• term_read (str) – List of possible single-char terminator for reading operations (speci-
fies when readline() stops).
• connect_on_operation (bool) – If True, the connection is normally closed, and is
opened only on the operations (normally two processes can’t be simultaneously connected
to the same device).
• open_retry_times (int) – Number of times the connection is attempted before giving
up.
• no_dtrrts (bool) – If True, turn off DTR and RTS status lines before opening (e.g.,
turns off reset-on-connection for Arduino controllers).
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError
Base class for the errors raised by the backend operations
alias of object
Error
alias of DeviceSerialError
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
single_op()
Context manager for a single operation.
If connect_on_operation==True during creation, wrapping several command in single_op prevents
the connection from being closed and reopened between the operations (only opened in the beginning and
closed in the end).
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
readline(remove_term=True, timeout=None, skip_empty=True, error_on_timeout=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• skip_empty (bool) – If True, ignore empty lines (works only for
remove_term==True).
• error_on_timeout (bool) – If False, return an incomplete line instead of raising
the error on timeout.
read(size=None)
Read data from the device.
If size is not None, read size bytes (usual timeout applies); otherwise, read all available data (return imme-
diately).
read_multichar_term(term, remove_term=True, timeout=None, error_on_timeout=True)
Read a single line with multiple possible terminators.
Parameters
• term – Either a string (single multi-char terminator) or a list of strings (multiple ter-
minators).
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• error_on_timeout (bool) – If False, return an incomplete line instead of raising
the error on timeout.
write(data, flush=True, read_echo=False, read_echo_delay=0, read_echo_lines=1)
Write data to the device.
If flush==True, flush the write buffer. If read_echo==True, wait for read_echo_delay seconds and
then perform readline() (read_echo_lines times).
static list_resources(desc=False)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
ask(query, delay=0.0, read_all=False)
Perform a write followed by a read, with delay in between.
If read_all==True, read all the available data; otherwise, read a single line.
classmethod combine_conn(conn1, conn2)
Combined two connection parameters into a single dictionary (conn1 overrides conn2)
cooldown(kind='default')
Cooldown between the operations.
kind specifies the operation kind (common kinds are open, close, read, write, timeout, and flush);
"default" corresponds to the default cooldown (usually, specified as 0). Called automatically by various
backend operations, so usually there is no need to call explicitly.
flush_read()
Flush the device output (read all the available data; return the number of bytes read)
classmethod get_backend_name()
Get string representation of the backend (e.g., "serial", "visa", or "network")
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceFT232Error(exc)
Bases: DeviceBackendError
FT232 backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.FT232DeviceBackend(conn, timeout=10.0, term_write=None,
term_read=None, open_retry_times=3,
datatype='auto', reraise_error=None)
Bases: IDeviceCommBackend
FT232 backend (via pyft232).
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters. Can be either a string (for a port), or a list/tuple (port,
baudrate, bytesize, parity, stopbits, xonxoff, rtscts) supplied to the
serial connection (default is ('COM1',19200,8,'N',1,0,0,0)), or a dict with the same
parameters.
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations; appended to the data
• term_read (str) – List of possible single-char terminator for reading operations (speci-
fies when readline() stops).
• open_retry_times (int) – Number of times the connection is attempted before giving
up.
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError
Base class for the errors raised by the backend operations
alias of object
Error
alias of DeviceFT232Error
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
single_op()
Context manager for a single operation.
Does nothing.
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
readline(remove_term=True, timeout=None, skip_empty=True, error_on_timeout=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• skip_empty (bool) – If True, ignore empty lines (works only for
remove_term==True).
• error_on_timeout (bool) – If False, return an incomplete line instead of raising
the error on timeout.
read(size=None)
Read data from the device.
If size is not None, read size bytes (usual timeout applies); otherwise, read all available data (return imme-
diately).
read_multichar_term(term, remove_term=True, timeout=None, error_on_timeout=True)
Read a single line with multiple possible terminators.
Parameters
• term – Either a string (single multi-char terminator) or a list of strings (multiple ter-
minators).
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• error_on_timeout (bool) – If False, return an incomplete line instead of raising
the error on timeout.
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceNetworkError(exc)
Bases: DeviceBackendError
Network backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.NetworkDeviceBackend(conn, timeout=10.0,
term_write=None, term_read=None,
datatype='auto',
reraise_error=None)
Bases: IDeviceCommBackend
Serial backend (via pySerial).
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters. Can be either a string "IP:port" (e.g., "127.0.0.
1:80"), or a tuple (IP,port), where IP is a string and port is a number.
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations; appended to the data
• term_read (str) – List of possible single-char terminator for reading operations (speci-
fies when readline() stops).
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
Note: If term_read is a string, its behavior is different from the VISA backend: instead of being a multi-char
terminator it is assumed to be a set of single-char terminators. If multi-char terminator is required, term_read
should be a single-element list instead of a string.
BackendError
Base class for the errors raised by the backend operations
alias of OSError
Error
alias of DeviceNetworkError
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
readline(remove_term=True, timeout=None, skip_empty=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• skip_empty (bool) – If True, ignore empty lines (works only for
remove_term==True).
read(size=None)
Read data from the device.
If size is not None, read size bytes (usual timeout applies); otherwise, read all available data (return imme-
diately).
read_multichar_term(term, remove_term=True, timeout=None)
Read a single line with multiple possible terminators.
Parameters
• term – Either a string (single multi-char terminator) or a list of strings (multiple ter-
minators).
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
write(data, flush=True, read_echo=False, read_echo_delay=0, read_echo_lines=1)
Write data to the device.
If read_echo==True, wait for read_echo_delay seconds and then perform readline() (read_echo_lines
times). flush parameter is ignored.
ask(query, delay=0.0, read_all=False)
Perform a write followed by a read, with delay in between.
If read_all==True, read all the available data; otherwise, read a single line.
classmethod combine_conn(conn1, conn2)
Combined two connection parameters into a single dictionary (conn1 overrides conn2)
cooldown(kind='default')
Cooldown between the operations.
kind specifies the operation kind (common kinds are open, close, read, write, timeout, and flush);
"default" corresponds to the default cooldown (usually, specified as 0). Called automatically by various
backend operations, so usually there is no need to call explicitly.
flush_read()
Flush the device output (read all the available data; return the number of bytes read)
classmethod get_backend_name()
Get string representation of the backend (e.g., "serial", "visa", or "network")
static list_resources(desc=False)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceUSBError(exc)
Bases: DeviceBackendError
USB backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.PyUSBDeviceBackend(conn, timeout=10.0, term_write=None,
term_read=None,
check_read_size=True, datatype='auto',
reraise_error=None)
Bases: IDeviceCommBackend
USB backend (via PyUSB package).
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters. Can be either a string (for a port), or a list/tuple
(vendorID, productID, index, endpoint_read, endpoint_write,
backend) supplied to the connection (default is (0x0000,0x0000,0,0x00,0x01,
'libusb1'), which is invalid for most devices), or a dict with the same parameters.
vendorID and productID specify device kind, index is an integer index (starting
from zero) of the device among several identical (i.e., with the same ids) ones, and
endpoint_read and endpoint_write specify connection endpoints for the specific
device.
• timeout (float) – Default timeout (in seconds).
• term_write (str) – Line terminator for writing operations; appended to the data
• term_read (str) – List of possible single-char terminator for reading operations (speci-
fies when readline() stops).
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError
Base class for the errors raised by the backend operations
alias of USBError
Error
alias of DeviceUSBError
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
set_timeout(timeout)
Set operations timeout (in seconds)
get_timeout()
Get operations timeout (in seconds)
readline(remove_term=True, timeout=None, skip_empty=True, error_on_timeout=True)
Read a single line from the device.
Parameters
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceHIDError(exc)
Bases: DeviceBackendError
HID backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.HIDeviceBackend(conn, timeout=10.0, term_write=None,
term_read=None, datatype='auto',
reraise_error=None)
Bases: IDeviceCommBackend
HID backend (via Windows DLLs).
Connection is automatically opened on creation.
Parameters
• conn – Connection parameters. Can be either a string (for a port), or a list/tuple
(vendorID, productID, index, endpoint_read, endpoint_write,
backend) supplied to the connection (default is (0x0000,0x0000,0,0x00,0x01,
'libusb1'), which is invalid for most devices), or a dict with the same parameters.
vendorID and productID specify device kind, index is an integer index (starting
from zero) of the device among several identical (i.e., with the same ids) ones, and
endpoint_read and endpoint_write specify connection endpoints for the specific
device.
• term – Either a string (single multi-char terminator) or a list of strings (multiple ter-
minators).
• remove_term (bool) – If True, remove terminal characters from the result.
• timeout – Operation timeout. If None, use the default device timeout.
• error_on_timeout (bool) – If False, return an incomplete line instead of raising
the error on timeout.
get_pending()
Get the number of bytes in the read buffer
write(data, flush=True, read_echo=False, read_echo_delay=0, read_echo_lines=1)
Write data to the device.
If read_echo==True, wait for read_echo_delay seconds and then perform readline() (read_echo_lines
times). flush parameter is ignored.
static list_resources(desc=False, **kwargs)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
ask(query, delay=0.0, read_all=False)
Perform a write followed by a read, with delay in between.
If read_all==True, read all the available data; otherwise, read a single line.
classmethod combine_conn(conn1, conn2)
Combined two connection parameters into a single dictionary (conn1 overrides conn2)
cooldown(kind='default')
Cooldown between the operations.
kind specifies the operation kind (common kinds are open, close, read, write, timeout, and flush);
"default" corresponds to the default cooldown (usually, specified as 0). Called automatically by various
backend operations, so usually there is no need to call explicitly.
flush_read()
Flush the device output (read all the available data; return the number of bytes read)
classmethod get_backend_name()
Get string representation of the backend (e.g., "serial", "visa", or "network")
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
exception pylablib.core.devio.comm_backend.DeviceRecordedError(exc)
Bases: DeviceBackendError
Recorded backend operation error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
class pylablib.core.devio.comm_backend.RecordedDeviceBackend(conn, datatype='auto',
reraise_error=None)
Bases: IDeviceCommBackend
Recorded backend.
Connection is automatically opened on creation.
Parameters
• conn – connection parameters (recorded log path)
• datatype (str) – Type of the returned data; can be "bytes" (return bytes object), "str"
(return str object), or "auto" (default Python result: str in Python 2 and bytes in Python
3)
• reraise_error – if not None, specifies an error to be re-raised on any backend exception
(by default, use backend-specific error); should be a subclass of DeviceBackendError.
BackendError
alias of OSError
Error
alias of DeviceRecordedError
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
start(header)
Start recorded section
stop()
Stop logging section
section(header)
static list_resources(desc=False)
List all available resources for this backend.
If desc==False, return list of connections (usually strings or tuples), which can be used to connect to the
device. Otherwise, return a list of descriptions, which have more info, but can be backend-dependent.
Might not be implemented (depending on the backend), in which case returns None.
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
readlines(lines_num, remove_term=True, timeout=None, skip_empty=True)
Read multiple lines from the device.
Parameters are the same as in readline().
set_timeout(timeout)
Set operations timeout (in seconds)
setup_cooldown(**kwargs)
Setup cooldown times for various operations.
The arguments are of the form kind=value, where value is the cooldown time (in seconds), and kind
is the operation kind (common kinds are open, close, read, write, timeout, and flush). kind
can also be default (default value for all kind), or all (reset all cooldown values to this value). The
cooldowns of the given kinds are usually called after the corresponding operation (it is necessary for some
devices, otherwise the communication can freeze or crush). Default cooldown values are specified by
_default_operation_cooldown class attribute dictionary.
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
using_timeout(timeout=None)
Context manager for usage of a different timeout inside a block
pylablib.core.devio.comm_backend.autodetect_backend(conn, default='visa')
Try to determine the backend by the connection.
default specifies the default backend which is returned if the backend is unclear.
pylablib.core.devio.comm_backend.new_backend(conn, backend='auto', defaults=None, **kwargs)
Build new backend with the supplied parameters.
Parameters
• conn – Connection parameters (depend on the backend). Can be simply connection
parameters (tuple or dict) for the given backend (e.g., "192.168.0.1" or ("COM1",
19200)), a tuple (backend, conn) which specifies both backend and connection (in
which case it overrides the supplied backend), or an already opened backend (in which
case it is returned as is)
• backend (str) – Backend type. Available backends are 'auto' (try to autodetect based
on the connection), 'visa', 'serial', 'ft232', 'network', and "pyusb". Can also
be directly a backend class (more appropriate for custom backends), or a tuple ('auto',
backend), which is analogous to 'auto', but it returns the specified backend if the
autodetection fails; by default, the fallback backend is 'visa', so 'auto' is exactly the
same as ('auto', 'visa').
• defaults – if not None, specifies a dictionary {backend: params} with default con-
nection parameters (depending on the backend), which are added to the connection pa-
rameters
• **kwargs – parameters sent to the backend.
pylablib.core.devio.comm_backend.backend_error(backend, conn=None)
Return error class corresponding to the current backend.
Like new_backend(), allows setting backend="auto", in which case conn is used to try and autodetect the
backend kind (not completely reliable, should be avoided).
pylablib.core.devio.comm_backend.list_backend_resources(backend=None, desc=False)
List all resources for the given backend.
If backend is None, return dictionary {backend: resources} for all available backends. If desc==False,
return list of connections (usually strings or tuples), which can be used to connect to the device. Otherwise,
return a list of descriptions, which have more info, but can be backend-dependent.
class pylablib.core.devio.comm_backend.ICommBackendWrapper(instr)
Bases: IDevice
A base class for an instrument using a communication backend.
Parameters
instr – Backend (assumed to be already opened).
apply_settings(settings)
Apply the settings.
settings is the dict {name: value} of the device available settings. Non-applicable settings are ignored.
get_device_variable(key)
Get the value of a settings, status, or full info parameter
get_full_info(include=0)
Get dict {name: value} containing full device information (including status and settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_full_status(include=0)
Get dict {name: value} containing the device status (including settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_settings(include=0)
Get dict {name: value} containing all the device settings.
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
set_device_variable(key, value)
Set the value of a settings parameter
open()
Open the backend
close()
Close the backend
is_opened()
Check if the device is connected
lock(timeout=None)
Lock the access to the device from other threads/processes (isn’t necessarily implemented)
unlock()
Unlock the access to the device from other threads/processes (isn’t necessarily implemented)
locking(timeout=None)
Context manager for lock & unlock
pylablib.core.devio.data_format module
Library for binary data encoding/decoding for device communication and dealing with different data format represen-
tations in different contexts (numpy, SCPI, etc.).
class pylablib.core.devio.data_format.DataFormat(size, kind, byteorder)
Bases: object
Describes data encoding for device communications.
Parameters
• size (int) – Size of a single element (in bytes).
• kind (str) – Kind of the element. Can be 'i' (integer), 'u' (unsigned integer), 'f'
(floating point) or 'ascii' (text representation).
• byteorder (str) – Byte order: '>' is big-endian (MSB first), '<' is little-endian (LSB
first).
flip_byteorder()
Flip byteorder of the description
is_ascii()
Check of the format is textual
static from_desc(desc, str_type='numpy')
Build the format from the string description.
str_type is the description format. Can be 'numpy' (numpy dtype description), 'struct' (struct de-
scription) or 'SCPI' (the standard SCPI description).
static from_desc_SCPI(desc, border='norm')
Build the format from the string SCPI description.
border describes byte order (either 'norm' or 'swap').
to_desc(str_type='auto')
Build a description string of this format.
str_type can be 'auto' (similar to 'numpy', but also accepts 'ascii'), 'numpy', 'struct' or 'SCPI'
(return tuple (desc, border)).
convert_from_str(data)
Convert the string data into an array
convert_to_str(data, ascii_format='.5f')
Convert the array into a string data.
ascii_format is the str.format() string for textual representation.
pylablib.core.devio.hid module
path
product
product_id
serial
vendor_id
version
pylablib.core.devio.hid.list_devices()
List HID devices.
Return list of tuples (path, manufacturer, product, serial, vendor_id, product_id, version),
where path is the string path used for connection.
class pylablib.core.devio.hid.HIDevice(path, timeout=3.0, rep_fmt='lenpfx', pause_on_write=True)
Bases: object
Generic HID-based device interface.
Parameters
• path – HID path (usually obtained using hid.list_devices())
• timeout – communication timeout
• rep_fmt – HID report format; can be "raw" (read/write raw data from/to HID),
"lenpfx" (assume a format where the first byte for the report indicates the payload size),
or a tuple (parser, builder) of two functions, where the parser takes a single raw
report data argument and returns a parsed value, while builder takes 2 arguments (data
to be written and the output report size) and return the bytes to be sent to HID.
• pause_on_write – if True, pause the reading loop when writing; makes some commu-
nications more stable
open()
Open the device connection if it is not opened yet
close()
Close the device connection
is_opened()
Check if the device connection is opened
get_description()
Get device description
Return tuple (path, manufacturer, product, serial, vendor_id, product_id, version),
where path is the string path used for connection.
get_timeout()
Get device communication timeout
set_timeout(timeout)
Set device communication timeout
class Reader(f , caps, buffsize, parser)
Bases: object
loop_read()
start_loop()
Start the read loop
stop_loop()
Stop the read loop
pausing(do_pause=True, timeout=None)
pylablib.core.devio.hid_base module
exception pylablib.core.devio.hid_base.HIDError
Bases: RuntimeError
Generic HID error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
exception pylablib.core.devio.hid_base.HIDLibError(func, code)
Bases: HIDError
Generic HID library boolean function error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
exception pylablib.core.devio.hid_base.HIDTimeoutError
Bases: HIDError
HID read timeout error
add_note()
Exception.add_note(note) – add a note to the exception
args
with_traceback()
Exception.with_traceback(tb) – set self.__traceback__ to tb and return self.
pylablib.core.devio.interface module
class pylablib.core.devio.interface.IDevice
Bases: object
A base class for an instrument.
Contains some useful functions for dealing with device settings.
open()
Open the connection
close()
Close the connection
is_opened()
Check if the device is connected
get_settings(include=0)
Get dict {name: value} containing all the device settings.
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_full_status(include=0)
Get dict {name: value} containing the device status (including settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
get_full_info(include=0)
Get dict {name: value} containing full device information (including status and settings).
include specifies either a list of variables (only these variables are returned), a priority threshold (only val-
ues with the priority equal or higher are returned), or "all" (all available variables). Since the lowest pri-
ority is -10, setting include=-10 queries all available variables, which is equivalent to include="all".
apply_settings(settings)
Apply the settings.
settings is the dict {name: value} of the device available settings. Non-applicable settings are ignored.
get_device_variable(key)
Get the value of a settings, status, or full info parameter
set_device_variable(key, value)
Set the value of a settings parameter
class pylablib.core.devio.interface.IParameterClass(name)
Bases: object
A generic parameter class.
Deals with converting device interface representation and the ‘internal’ representation (e.g., names used in SCPI
commands or integer indices). Also responsible for validating the user-passed and device-returned parameters.
Needs to define to methods: __call__ for converting user parameters (‘alias’) into the device parameters
(‘value’) and i() for the opposite conversion. In addition, it provides using_device() context manager to
temporarily change the device attribute, which can be used by some parameter classes for device-dependent
conversions.
Parameters
name – parameter class name; used to match method arguments with corresponding classes.
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
docstring()
Get a parameter docstring
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
class pylablib.core.devio.interface.ICheckingParameterClass(name)
Bases: IParameterClass
Parameter class which separately handles checking and conversion.
Specifies six methods: check_value(), to_alias() and _value_error_str for handling value-to-alias con-
version, and check_alias(), to_value() and _alias_error_str for handling alias-to-value conversion.
check_alias(alias)
Check if the alias is valid
check_value(value)
Check if the device value is valid
to_value(alias)
Convert the alias into a device value
to_alias(value)
Convert the device value into an alias
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
docstring()
Get a parameter docstring
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
class pylablib.core.devio.interface.RangeParameterClass(name, minval=None, maxval=None,
out_of_range='error')
Bases: ICheckingParameterClass
Parameter class for numerical values constrained to a certain range.
Parameters
• name – parameter class name
• minval – minimal allowed value (inclusive); None means no lower limit
• maxval – maximal allowed value (inclusive); None means no upper limit
• out_of_range – action if an out-of-range value is supplied; can be either "error" (raise
an error), or "truncate" (truncate to the nearest limit).
check_value(value)
Check if the device value is valid
check_alias(alias)
Check if the alias is valid
to_value(alias)
Convert the alias into a device value
docstring()
Get a parameter docstring
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
to_alias(value)
Convert the device value into an alias
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
class pylablib.core.devio.interface.IEnumParameterClass(name, allowed_alias='device_values',
allowed_value='exact', alias_case=None,
value_case=None, match_prefix=False)
Bases: ICheckingParameterClass
Parameter class for a generic enum (i.e., predefined values) parameter.
Defines two methods for handling conversion:
• _get_value_map which returns a dictionary for converting device values into aliases,
• _get_alias_map which returns a dictionary for converting aliases into device values.
These methods need to be redefined in subclasses.
Parameters
• name – parameter class name
• allowed_alias – specifies a range of allowed aliases; can be "exact" (only exact map
matches are allowed), "device_value" (exact map matches and raw device values are
allowed), or "all" (all values are allowed); in the latter two cases the value not in the
map are passed as is.
• allowed_value – specifies a range of allowed device values; can be "exact" (only exact
map matches are allowed), or "all" (all values are allowed); in the latter case the value
not in the map is passed as is.
• alias_case – default alias parameter case for string values; can be None (no case nor-
malization), or "lower" or "upper" (any received or returned alias will be normalized
into this case)
• value_case – default value parameter case for string values; can be None (no case nor-
malization), or "lower" or "upper" (any received or returned device value will be nor-
malized into this case)
• match_prefix – if True, then the keys in the value map (returned by _get_value_map
method) are interpreted as prefixes, so in the value-to-alias conversion the converted value
matches the map value if it just starts with it; in the case of ambiguity (several map values
are prefixes for the same converted value), the exact match takes priority; useful for some
SCPI devices, where the shorter version of the value can sometimes be returned.
check_value(value)
Check if the device value is valid
check_alias(alias)
Check if the alias is valid
to_value(alias)
Convert the alias into a device value
to_alias(value)
Convert the device value into an alias
docstring()
Get a parameter docstring
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
class pylablib.core.devio.interface.EnumParameterClass(name, alias_map, value_map=None,
allowed_alias='device_values',
allowed_value='exact', alias_case=None,
value_case=None, match_prefix=False)
Bases: IEnumParameterClass
Parameter class for a enum (i.e., predefined values) parameter with the specified mapping.
Parameters
• name – parameter class name
• alias_map – mapping of aliases to device values; can be a dictionary, or a list of (alias,
value) tuples (in the latter case non-tuple values are also allowed, indicating that value is
the same as the alias); the list representation is useful in cases where the same alias maps
to more than one value, so the map inversion is impossible
• value_map – mapping of device values to aliases; can only be a dictionary or None, which
means that the alias map is automatically inverted
• allowed_alias – specifies a range of allowed aliases; can be "exact" (only exact map
matches are allowed), "device_value" (exact map matches and raw device values are
allowed), or "all" (all values are allowed); in the latter two cases the value not in the
map are passed as is.
• allowed_value – specifies a range of allowed device values; can be "exact" (only exact
map matches are allowed), or "all" (all values are allowed); in the latter case the value
not in the map is passed as is.
• alias_case – default alias parameter case for string values; can be None (no case nor-
malization), or "lower" or "upper" (any received or returned alias will be normalized
into this case)
• value_case – default value parameter case for string values; can be None (no case nor-
malization), or "lower" or "upper" (any received or returned device value will be nor-
malized into this case)
• match_prefix – if True, then the keys in the value map (or values in the alias map, if only
it is provided) are assumed to br prefixes, so in the value-to-alias conversion the converted
value matches the map value if it just starts with it; useful for some SCPI devices, where
the shorter version of the value can sometimes be returned.
check_alias(alias)
Check if the alias is valid
check_value(value)
Check if the device value is valid
docstring()
Get a parameter docstring
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
to_alias(value)
Convert the device value into an alias
to_value(alias)
Convert the alias into a device value
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
class pylablib.core.devio.interface.FunctionParameterClass(name, to_alias=None, to_value=None,
check_value=None, check_alias=None,
alias_err=None, value_err=None)
Bases: ICheckingParameterClass
Parameter class which uses supplied methods for checking, conversion, and generating error messages.
The arguments correspond to the parameter methods with the same names. When not supplied, checking methods
always return True, conversion methods leave value intact, and error string methods generate the default error
messages.
check_value(value)
Check if the device value is valid
check_alias(alias)
Check if the alias is valid
to_alias(value)
Convert the device value into an alias
to_value(alias)
Convert the alias into a device value
docstring()
Get a parameter docstring
i(value, device=None)
Convert device parameter value into a corresponding use parameter value
If not None, device specifies the corresponding device instance for device-dependent conversion.
using_device(device)
Context manager for temporarily changing the device attribute to the given device instance
class pylablib.core.devio.interface.CombinedParameterClass(name, parameters)
Bases: IParameterClass
A multi-stage combined parameter class, which performs several conversion/check stages.
Parameters
pylablib.core.devio.interface.pval(value)
Mark that the value has already been treated by the parameter class
pylablib.core.devio.interface.use_parameters(*args, **kwargs)
Wrapper to indicate that a device class method uses device parameter classes.
The corresponding parameters classes are automatically determined if the argument name matches the parameter
class name. The parameters classes can also be defined explicitly using keywords arguments arg=parameter
supplied to the wrapper, where arg is the argument, and parameter is either a parameter class instance, or
a parameter class name (the more preferable way). In addition, an argument _returns can be used to define
the parameter class for the return value; it can also be a list or a tuple of parameter classes, indicating that the
returned value is also a list or a tuple.
Module contents
pylablib.core.fileio package
Submodules
pylablib.core.fileio.datafile module
pylablib.core.fileio.dict_entry module
Classes for dealing with the Dictionary entries with special conversion rules when saved or loaded. Used to redefine
how certain objects (e.g., tables) inside dictionaries are written into files and read from files.
pylablib.core.fileio.dict_entry.is_dict_entry_branch(branch)
Check if the dictionary branch contains a dictionary entry which needs to be specially converted.
class pylablib.core.fileio.dict_entry.DictEntryBuilder(entry_cls, pred=None, **kwargs)
Bases: object
Object for building dictionary entries from objects.
Parameters
• entry_cls – dictionary entry class
• pred – method used to check if an object can be turned into the corresponding entry; if
None, use the default entry class checker (entry_class.is_data_valid)
• kwargs – keyword arguments passed to the entry constructor along with the data
is_data_valid(data)
Check if a data object can be wrapped by the current entry class
from_data(data)
Build a dictionary entry from the data
class pylablib.core.fileio.dict_entry.DictEntryParser(entry_cls, pred=None, **kwargs)
Bases: object
Object for building dictionary entries from dictionary branches.
Parameters
• entry_cls – dictionary entry class
• pred – method used to check if a dictionary branch can be turned into the corresponding
entry; if None, use the default entry class checker (entry_class.is_branch_valid)
• kwargs – keyword arguments passed to the entry from_dict class method along with
the branch
is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
from_dict(dict_ptr, loc)
Build a dictionary entry from the branch and the file location
pylablib.core.fileio.dict_entry.add_dict_entry_builder(builder)
Add an entry builder to the global list of builders
pylablib.core.fileio.dict_entry.add_dict_entry_parser(parser)
Add an entry parser to the global list of parsers
pylablib.core.fileio.dict_entry.add_dict_entry_class(cls)
Add an entry class.
Automatically registers builder and parser, which take no additional arguments and use default class method to
determine if an object/branch can be converted into an entry.
pylablib.core.fileio.dict_entry.from_data(data, builders=None)
Build a dictionary entry from the data.
builders can contain an additional list of builder to try before using the default ones.
pylablib.core.fileio.dict_entry.from_dict(dict_ptr, loc, parsers=None)
Build a dictionary entry from the dictionary branch and the file location.
parsers can contain an additional list of parsers to try before using the default ones.
class pylablib.core.fileio.dict_entry.IDictionaryEntry(data)
Bases: object
A generic Dictionary entry.
Contains data represented by the node, as well as the way to represent this data as a dictionary branch.
Parameters
data – data to be wrapped
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
classmethod from_dict(dict_ptr, loc)
Convert a dictionary branch to a specific IDictionaryEntry object.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
to_dict(dict_ptr, loc)
Convert data to a dictionary branch on saving.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – File location for the data to be saved.
pylablib.core.fileio.dict_entry.parse_stored_table_data(desc=None, data=None,
out_type='pandas')
Parse table data corresponding to the given description dictionary and data.
Parameters
• desc – description dictionary; can be None, if no description is given
• data – separately loaded data; can be None, if no data is given (in this case assume that it
is stored in the description dictionary); can be a tuple (column_data, column_names)
(such as the one returned by parse_csv.read_table()), or a an InlineTable object
containing such tuple.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects).
Returns
tuple (data, columns), where data is the data table in the specified format, and columns
is the list of columns
class pylablib.core.fileio.dict_entry.ITableDictionaryEntry(data, columns=None)
Bases: IDictionaryEntry
A generic table Dictionary entry.
Parameters
• data – Table data.
• columns (list) – If not None, list of column names (if None and data is a pandas
DataFrame object, get column names from that).
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
classmethod from_dict(dict_ptr, loc, out_type='pandas')
Convert a dictionary branch to a specific DictionaryEntry object.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects), used only if the dictionary doesn’t provide the format.
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
to_dict(dict_ptr, loc)
Convert data to a dictionary branch on saving.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – File location for the data to be saved.
class pylablib.core.fileio.dict_entry.InlineTableDictionaryEntry(data, columns=None)
Bases: ITableDictionaryEntry
An inlined table Dictionary entry.
Parameters
• data – Table data.
• columns (list) – If not None, a list of column names (if None and data is a pandas
DataFrame object, get column names from that).
to_dict(dict_ptr, loc)
Convert the data to a dictionary branch and write the table to the file.
classmethod from_dict(dict_ptr, loc, out_type='pandas')
Build an InlineTableDictionaryEntry object from the dictionary and read the inlined data.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects).
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
class pylablib.core.fileio.dict_entry.IExternalTableDictionaryEntry(data, file_format, name,
columns,
force_name=True)
Bases: ITableDictionaryEntry
classmethod from_dict(dict_ptr, loc, out_type='pandas')
Convert a dictionary branch to a specific DictionaryEntry object.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects), used only if the dictionary doesn’t provide the format.
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
to_dict(dict_ptr, loc)
Convert data to a dictionary branch on saving.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – File location for the data to be saved.
class pylablib.core.fileio.dict_entry.ExternalTextTableDictionaryEntry(data=None,
file_format='csv',
name='',
columns=None,
force_name=True)
Bases: IExternalTableDictionaryEntry
An external text table Dictionary entry.
Parameters
• data – Table data.
• file_format (str) – Output file format.
• name (str) – Name template for the external file (default is the full path connected with
"_" symbol).
• columns (list) – If not None, a list of column names (if None and data is a pandas
DataFrame object, get column names from that).
• force_name (bool) – If False and the target file already exists, generate a new unique
name; otherwise, overwrite the file.
to_dict(dict_ptr, loc)
Convert the data to a dictionary branch and save the table to an external file.
classmethod from_dict(dict_ptr, loc, out_type='pandas')
Build an ExternalTextTableDictionaryEntry object from the dictionary and load the external data.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects).
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
class pylablib.core.fileio.dict_entry.ExternalBinTableDictionaryEntry(data=None,
file_format='bin',
name='', columns=None,
force_name=True)
Bases: IExternalTableDictionaryEntry
An external binary table Dictionary entry.
Parameters
• data – Table data.
• file_format (str) – Output file format.
• name (str) – Name template for the external file (default is the full path connected with
"_" symbol).
• columns (list) – If not None, a list of column names (if None and data is a pandas
DataFrame object, get column names from that).
• force_name (bool) – If False and the target file already exists, generate a new unique
name; otherwise, overwrite the file.
to_dict(dict_ptr, loc)
Convert the data to a dictionary branch and save the table to an external file.
classmethod from_dict(dict_ptr, loc, out_type='pandas')
Build an ExternalBinTableDictionaryEntry object from the dictionary and load the external data.
Parameters
• dict_ptr (dictionary.DictionaryPointer) – Pointer to the dictionary location
for the entry.
• loc – Location for the data to be loaded.
• out_type (str) – Output format of the data ('array' for numpy arrays or 'pandas'
for pandas DataFrame objects).
classmethod is_branch_valid(branch)
Check if a branch can be parsed by the current entry class
classmethod is_data_valid(data)
Check if a data object can be wrapped by the current entry class
pylablib.core.fileio.dict_entry.table_entry_builder(table_format='inline')
Make an entry builder for tables depending on the table format.
Parameters
table_format (str) – Default format for table (numpy arrays or pandas DataFrames) entries.
Can be 'inline' (table is written inside the file), 'csv' (external CSV file) or 'bin' (external
binary file).
class pylablib.core.fileio.dict_entry.IExternalFileDictionaryEntry(data, name='',
force_name=True)
Bases: IDictionaryEntry
Generic dictionary entry for data in an external file.
Parameters
• data – Stored data.
• name (str) – Name template for the external file (default is the full path connected with
"_" symbol).
• force_name (bool) – If False and the target file already exists, generate a new unique
name; otherwise, overwrite the file.
file_format = None
static add_file_format(subclass)
Register an IExternalFileDictionaryEntry as a possible stored file format.
Used to automatically invoke a correct loader when loading the dictionary file. Only needs to be done once
after the subclass declaration.
to_dict(dict_ptr, loc)
Convert the data to a dictionary branch and save the data to an external file
classmethod from_dict(dict_ptr, loc)
Build an IExternalFileDictionaryEntry object from the dictionary and load the external data.
Parameters
get_preamble()
Generate preamble (dictionary with supplementary data which allows to load the data from the file)
save_file(location_file)
Save stored data into the given location
classmethod load_file(location_file, preamble)
Load stored data from the given location, using the supplied preamble
static add_file_format(subclass)
Register an IExternalFileDictionaryEntry as a possible stored file format.
Used to automatically invoke a correct loader when loading the dictionary file. Only needs to be done once
after the subclass declaration.
pylablib.core.fileio.loadfile module
read(location_file)
Read a file at a given location
class pylablib.core.fileio.loadfile.ITextInputFileFormat
Bases: IInputFileFormat
Generic class for a text input file format.
Based on file_format or autodetection, calls one of its subclasses to read the file.
static detect_file_format(location_file)
read(location_file)
Read a file at a given location
class pylablib.core.fileio.loadfile.CSVTableInputFileFormat(out_type='default', dtype='numeric',
columns=None, delimiters=None,
empty_entry_substitute=None,
ignore_corrupted_lines=True,
skip_lines=0)
Bases: ITextInputFileFormat
Class for CSV input file format.
Parameters
• out_type (str) – type of the result: 'array' for numpy array, 'pandas' for pandas
DataFrame, or 'default' (determined by the library default; 'pandas' by default)
• dtype – dtype of entries; can be either a single type, or a list of types (one per column).
Possible dtypes are: 'int', 'float', 'complex', 'numeric' (tries to coerce to mini-
mal possible numeric type, raises error if data can’t be converted to complex), 'generic'
(accept arbitrary types, including lists, dictionaries, escaped strings, etc.), 'raw' (keep
raw string).
• columns – either a number if columns, or a list of columns names.
• delimiters (str) – Regex string which recognizes entries delimiters (by default r"\
s*,\s*|\s+", i.e., commas and whitespaces).
• empty_entry_substitute – Substitute for empty table entries. If None, all empty table
entries are skipped.
• ignore_corrupted_lines (bool) – If True, skip corrupted (e.g., non-numeric for nu-
meric dtype, or with too few entries) lines; otherwise, raise ValueError.
• skip_lines (int) – Number of lines to skip from the beginning of the file.
read(location_file)
Read a file at a given location
static detect_file_format(location_file)
class pylablib.core.fileio.loadfile.DictionaryInputFileFormat(case_normalization=None,
inline_dtype='generic',
inline_out_type='default',
entry_format='value',
allow_duplicate_keys=False,
skip_lines=0)
Bases: ITextInputFileFormat
Class for Dictionary input file format.
Parameters
class pylablib.core.fileio.loadfile.BinaryTableInputFileFormatter(out_type='default',
dtype='<f8', columns=None,
packing='flatten',
preamble=None,
skip_bytes=0)
Bases: IInputFileFormat
Class for binary input file format.
Parameters
• location_file – Location of the data.
• out_type (str) – type of the result: 'array' for numpy array, 'pandas' for pandas
DataFrame, or 'default' (determined by the library default; 'pandas' by default)
• dtype – numpy.dtype describing the data.
• columns – either number if columns, or a list of columns names.
• packing (str) – The way the 2D array is packed. Can be either 'flatten' (data is
stored row-wise) or 'transposed' (data is stored column-wise).
• preamble (dict) – If not None, defines binary file parameters that supersede the parame-
ters supplied to the function. The defined parameters are 'dtype', 'packing', 'ncols'
(number of columns) and 'nrows' (number of rows).
• skip_bytes (int) – Number of bytes to skip from the beginning of the file.
read(location_file)
Read a file at a given location
static detect_file_format(location_file)
• inline_out_type (str) – type of the result of the inline table: 'array' for numpy
array, 'pandas' for pandas DataFrame, 'raw' for raw InlineTable data containing
tuple (column_data, column_names), or 'default' (determined by the library de-
fault; 'pandas' by default).
• entry_format (str) – Determines the way for dealing with dict_entry.
IDictionaryEntry objects (objects transformed into dictionary branches with
special recognition rules). Can be 'branch' (don’t attempt to recognize those object,
leave dictionary as in the file), 'dict_entry' (recognize and leave as dict_entry.
IDictionaryEntry objects) or 'value' (recognize and keep the value).
• allow_duplicate_keys (bool) – if False and the same key is mentioned twice in the
file, raise and error
• skip_lines (int) – Number of lines to skip from the beginning of the file.
• loc (str) – location type ("file" means the usual file location; see location.
get_location() for details)
• encoding – if a new file location is opened, this specifies the encoding
• return_file (bool) – if True, return DataFile object (contains some metainfo); oth-
erwise, return just the file data
pylablib.core.fileio.loadfile.load_generic(path=None, file_format=None, loc='file', encoding=None,
return_file=False, **kwargs)
Load data from the file.
Parameters
• path (str) – path to the file of a file-like object
• file_format (str) – input file format; if None, attempt to auto-detect file format (same
as 'generic'); can also be an IInputFileFormat instance for specific reading method
• loc (str) – location type ("file" means the usual file location; see location.
get_location() for details)
• encoding – if a new file location is opened, this specifies the encoding
• return_file (bool) – if True, return DataFile object (contains some metainfo); oth-
erwise, return just the file data
**kwargs are passed to the file formatter used to read the data (see CSVTableInputFileFormat,
DictionaryInputFileFormat and BinaryTableInputFileFormatter for the possible arguments). The
default format names are:
• 'generic': Generic file format. Attempt to autodetect, raise IOError if unsuccessful;
• 'txt': Generic text file. Attempt to autodetect, raise IOError if unsuccessful
• 'csv': CSV file, corresponds to CSVTableInputFileFormat;
• 'dict': Dictionary file, corresponds to DictionaryInputFileFormat;
• 'bin': Binary file, corresponds to BinaryTableInputFileFormatter
pylablib.core.fileio.loadfile_utils module
pylablib.core.fileio.loadfile_utils.detect_binary_file(stream)
Check if the opened file is binary
pylablib.core.fileio.loadfile_utils.test_row_type(line)
Try to determine whether the line is a comment line, a numerical data row, a dictionary row or an unrecognized
row.
Doesn’t distinguish with a great accuracy; useful only for trying to guess file format.
pylablib.core.fileio.loadfile_utils.detect_textfile_type(stream)
Try to autodetect text file type: dictionary or table
pylablib.core.fileio.loadfile_utils.test_savetime_comment(line)
Test if the comment resembles a savetime line
pylablib.core.fileio.loadfile_utils.find_savetime_comment(comments)
Try to find savetime comment
pylablib.core.fileio.loadfile_utils.test_columns_line(line, cols_num)
Test if the line looks like a list of columns for a given columns number
pylablib.core.fileio.loadfile_utils.find_columns_lines(corrupted, comments, cols_num)
Try to find a column line (for a given columns number) among the comment and corrupted lines
class pylablib.core.fileio.loadfile_utils.InlineTable(table)
Bases: object
Simple marker class that denotes that the wrapped numpy 2D array should be written inline
pylablib.core.fileio.loadfile_utils.parse_dict_line(line)
Parse stripped dictionary file line
pylablib.core.fileio.loadfile_utils.read_dict_and_comments(f , case_normalization=None,
inline_dtype='generic',
allow_duplicate_keys=False)
Load dictionary entries and comments from the file stream.
Parameters
• f – file stream
• case_normalization – case normalization for the returned dictionary; None means that
it’s case sensitive, "upper" and "lower" determine how they are normalized
• inline_dtype – dtype for inline tables; by default, use the most generic type (can include
Python objects such as lists or strings)
• allow_duplicate_keys – if False and the same key is listed twice, raise and error
Return tuple (data, comment_lines), where data is a dictionary with parsed entries (tables are still repre-
sented as ‘raw’, i.e., as a tuple of columns list and column names list), and comment_lines is a list of comment
lines
pylablib.core.fileio.location module
static from_object(obj)
Create a LocationName object from an object.
obj can be a LocationName (return unchanged), tuple or list (use as construct arguments), string (treat as
a string representation) or None (return empty name).
copy()
generate_new_name(prefix_name, idx=0)
close(name)
list_opened_files()
class pylablib.core.fileio.location.IFileSystemDataLocation(encoding=None)
Bases: IDataLocation
A generic filesystem data location.
A single file name describes a single file in the filesystem.
get_filesystem_path(name=None, path_type='absolute')
Get the filesystem path corresponding to a given name.
path_type can be 'absolute' (return absolute path), 'relative' (return relative path; level depends on
the location) or 'name' (only return path inside the location).
is_free(name=None)
Check if the name is unoccupied
open(name=None, mode='read', data_type='text')
Open a location file.
Parameters
• name – File name inside the location (None means ‘default’ location),
• mode (str) – Opening mode. Can be 'read', 'write' or 'append', as well as
standard abbreviation (e.g., "r" or "wb").
• data_type (str) – Either 'text' or 'binary'; if mode is an abbreviation, this
parameter is ignored (i.e., open("r","binary") still opens file as text).
close(name)
Close a location file
list_opened_files()
Get a dictionary {string_name: location_file} of all files opened in this location
generate_new_name(prefix_name, idx=0)
Generate a new name inside the location using the given prefix and starting index.
If idx is None, check just the prefix_name first before starting to append indices.
class pylablib.core.fileio.location.SingleFileSystemDataLocation(file_path, encoding=None)
Bases: IFileSystemDataLocation
A location describing a single file.
Any use of a non-default name raises ValueError.
Parameters
file_path (str) – The path to the file.
get_filesystem_path(name=None, path_type='absolute')
Get the filesystem path corresponding to a given name.
path_type can be 'absolute' (return absolute path), 'relative' (return relative path; level depends on
the location) or 'name' (only return path inside the location).
close(name)
Close a location file
generate_new_name(prefix_name, idx=0)
Generate a new name inside the location using the given prefix and starting index.
If idx is None, check just the prefix_name first before starting to append indices.
is_free(name=None)
Check if the name is unoccupied
list_opened_files()
Get a dictionary {string_name: location_file} of all files opened in this location
open(name=None, mode='read', data_type='text')
Open a location file.
Parameters
• name – File name inside the location (None means ‘default’ location),
• mode (str) – Opening mode. Can be 'read', 'write' or 'append', as well as
standard abbreviation (e.g., "r" or "wb").
• data_type (str) – Either 'text' or 'binary'; if mode is an abbreviation, this
parameter is ignored (i.e., open("r","binary") still opens file as text).
class pylablib.core.fileio.location.PrefixedFileSystemDataLocation(file_path,
prefix_template='{0}_{1}',
encoding=None)
Bases: IFileSystemDataLocation
A location describing a set of prefixed files.
Parameters
• file_path (str) – A master path. Its name is used as a prefix, and its extension is used
as a default.
• prefix_template (str) – A str.format() string for generating prefixed files. Has
two arguments: the first is the master name, the second is the sub_location.
Multi-level paths translate into nested folders (the top level folder is combined from the file_path prefix and the
first path entry).
get_filesystem_path(name=None, path_type='absolute')
Get the filesystem path corresponding to a given name.
path_type can be 'absolute' (return absolute path), 'relative' (return relative path; level depends on
the location) or 'name' (only return path inside the location).
close(name)
Close a location file
generate_new_name(prefix_name, idx=0)
Generate a new name inside the location using the given prefix and starting index.
If idx is None, check just the prefix_name first before starting to append indices.
is_free(name=None)
Check if the name is unoccupied
list_opened_files()
Get a dictionary {string_name: location_file} of all files opened in this location
open(name=None, mode='read', data_type='text')
Open a location file.
Parameters
• name – File name inside the location (None means ‘default’ location),
• mode (str) – Opening mode. Can be 'read', 'write' or 'append', as well as
standard abbreviation (e.g., "r" or "wb").
• data_type (str) – Either 'text' or 'binary'; if mode is an abbreviation, this
parameter is ignored (i.e., open("r","binary") still opens file as text).
class pylablib.core.fileio.location.FolderFileSystemDataLocation(folder_path,
default_name='content',
default_ext='',
encoding=None)
Bases: IFileSystemDataLocation
A location describing a single folder.
Parameters
• folder_path (str) – A path to the folder. Can also have one or two '|' symbols in the
end (e.g., 'folder|file|dat'), which separate default name and extension (overrides
default_name and default_ext parameters)
• default_name (str) – The default file name.
• default_ext (str) – The default file extension.
Multi-level paths translate into nested subfolders.
get_filesystem_path(name=None, path_type='absolute')
Get the filesystem path corresponding to a given name.
path_type can be 'absolute' (return absolute path), 'relative' (return relative path; level depends on
the location) or 'name' (only return path inside the location).
close(name)
Close a location file
generate_new_name(prefix_name, idx=0)
Generate a new name inside the location using the given prefix and starting index.
If idx is None, check just the prefix_name first before starting to append indices.
is_free(name=None)
Check if the name is unoccupied
list_opened_files()
Get a dictionary {string_name: location_file} of all files opened in this location
open(name=None, mode='read', data_type='text')
Open a location file.
Parameters
• name – File name inside the location (None means ‘default’ location),
• mode (str) – Opening mode. Can be 'read', 'write' or 'append', as well as
standard abbreviation (e.g., "r" or "wb").
• data_type (str) – Either 'text' or 'binary'; if mode is an abbreviation, this
parameter is ignored (i.e., open("r","binary") still opens file as text).
pylablib.core.fileio.location.get_location(path, loc, *args, **kwargs)
Build a location.
If path or loc are instances of IDataLocation, return them unchanged. If loc is a string, it describes location
kind:
• 'single_file': SingleFileSystemDataLocation with the given path.
• 'file' or 'prefixed_file': PrefixedFileSystemDataLocation with the given path as a master
path.
• 'folder': FolderFileSystemDataLocation with the given folder path.
Any additional arguments are relayed to the constructors.
pylablib.core.fileio.parse_csv module
convert_columns(raw_columns)
Convert raw columns into appropriate data structure (numpy array for numeric dtypes, list for generic and
raw).
add_columns(columns)
Append columns (lists or numpy arrays) to the existing data.
add_chunk(chunk)
Add a chunk (2D list) to the pre-existing data.
pylablib.core.fileio.parse_csv.read_columns(f , dtype, delimiters='\\s*,\\s*|\\s+',
empty_entry_substitute=None,
ignore_corrupted_lines=True, trim_rows=False,
stop_comment=None)
Load columns from the file stream f.
Parameters
• dtype – dtype of entries; can be either a single type, or a list of types (one per column).
Possible dtypes are: 'int', 'float', 'complex', 'numeric' (tries to coerce to mini-
mal possible numeric type, raises error if data can’t be converted to complex), 'generic'
(accept arbitrary types, including lists, dictionaries, escaped strings, etc.), 'raw' (keep
raw string).
• delimiters (str) – Regex string which recognizes delimiters (by default r"\s*,\s*|\
s+", i.e., commas and whitespaces).
• empty_entry_substitute – Substitute for empty table entries. If None, all empty table
entries are skipped.
• ignore_corrupted_lines – If True, skip corrupted (e.g., non-numeric for numeric
dtype, or with too few entries) lines; otherwise, raise ValueError.
• trim_rows – if True and the row length is larger than expected, drop extra entries; oth-
erwise, treat the row as corrupted
• stop_comment (str) – Regex string for the stopping comment. If not None. the function
will stop if comment satisfying stop_comment regex is encountered.
Returns
(columns, comments, corrupted_lines).
columns is a list of columns with data.
comments is a list of comment strings.
corrupted_lines is a dict {'size':list, 'type':list} of corrupted lines (al-
ready split into entries), based on the corruption type ('size' means too small size,
'type' means it couldn’t be converted using provided dtype).
Return type
tuple
pylablib.core.fileio.savefile module
write_data(location_file, data)
write(location_file, data)
• save_props (bool) – If True and saving datafile.DataFile object, save its props
metainfo.
• save_comments (bool) – If True and saving datafile.DataFile object, save its com-
ments metainfo.
• save_time (bool) – If True, append the file creation time in the end.
• new_time (bool) – If saving datafile.DataFile object, determines if the time should
be updated to the current time.
make_comment_line(comment)
make_prop_line(name, value)
make_savetime_line(time)
write_comments(stream, comments)
write_props(stream, props)
write_savetime(stream, time)
write_file(location_file, to_save)
write(location_file, data)
write_data(location_file, data)
get_table_line(line)
get_columns_line(columns)
write_data(location_file, data)
Write data to a CSV file.
Parameters
• location_file – Location of the destination.
• data – Data to be saved. Can be a pandas DataFrame or an arbitrary 2D array (numpy
array, 2D list, etc.); if the data is not DataFrame or numpy 2D array, it gets converted
into a DataFrame using the standard constructor (i.e., 2D list is interpreted as a list of
rows)
make_comment_line(comment)
make_prop_line(name, value)
make_savetime_line(time)
write(location_file, data)
write_comments(stream, comments)
write_file(location_file, to_save)
write_props(stream, props)
write_savetime(stream, time)
class pylablib.core.fileio.savefile.DictionaryOutputFileFormat(param_formats=None,
use_rep_classes=False,
table_format='inline',
inline_delimiters='\t',
inline_formats=None,
save_props=True,
save_comments=True,
save_time=True)
Bases: ITextOutputFileFormat
Class for Dictionary output file format.
Parameters
• param_formats (str) – If not None, defines value formats to be passed to utils.
string.to_string() function when writing Dictionary entries.
• use_rep_classes (bool) – If True, use representation classes for Dictionary entries
(e.g., numpy arrays will be represented as "array([1, 2, 3])" instead of just "[1,
2, 3]"); This improves storage fidelity, but makes result harder to parse (e.g., by external
string parsers).
• table_format (str) – Default format for table (numpy arrays or pandas DataFrames)
entries. Can be 'inline' (table is written inside the file), 'csv' (external CSV file) or
'bin' (external binary file).
• inline_delimiters (str) – Used to separate entries in a row for inline tables.
write_data(location_file, data)
Write data to a Dictionary file.
Parameters
• location_file – Location of the destination.
• data – Data to be saved. Should be object of class Dictionary.
make_comment_line(comment)
make_prop_line(name, value)
make_savetime_line(time)
write(location_file, data)
write_comments(stream, comments)
write_file(location_file, to_save)
write_props(stream, props)
write_savetime(stream, time)
class pylablib.core.fileio.savefile.IBinaryOutputFileFormat(format_name)
Bases: IOutputFileFormat
get_preamble(location_file, data)
write(location_file, data)
write_data(location_file, data)
write_file(location_file, to_save)
get_dtype(table)
get_preamble(location_file, data)
Generate a preamble (dictionary describing the file format).
The parameters are 'dtype', 'packing' ('transposed' or 'flatten', depending on the transposed
attribute), 'ncol' (number of columns) and 'nrows' (number of rows).
write_data(location_file, data)
Write data to a binary file.
Parameters
• location_file – Location of the destination.
• data – Data to be saved. Can be a pandas DataFrame or an arbitrary 2D array (numpy
array, 2D list, etc.) Converted to numpy array before saving.
write_file(location_file, to_save)
write(location_file, data)
pylablib.core.fileio.table_stream module
Module contents
pylablib.core.gui package
Subpackages
pylablib.core.gui.widgets package
Submodules
pylablib.core.gui.widgets.button module
class pylablib.core.gui.widgets.button.ToggleButton(parent=None)
Bases: object
Expanded toggle button.
Maintains internally stored consistent value (which can be, e.g., accessed from different threads). Allows setting
different captions of pressed/unpressed, and uses those to represent values.
set_value_labels(labels)
Set a list of values corresponding to combo box indices.
Can be either a list of values, whose length must be equal to the number of options, or None (don’t change
the button label on toggle).
value_changed = <Mock name='mock.QtCore.pyqtSignal()' id='140527858977616'>
Signal emitted when value is changed
get_value()
Get current value
set_value(value, notify_value_change=True)
Set current value.
If notify_value_change==True, emit the value_changed signal; otherwise, change value silently.
repr_value(value)
Return representation of value as a caption text
pylablib.core.gui.widgets.button_selector module
class pylablib.core.gui.widgets.button_selector.ButtonSelector(parent)
Bases: object
Button selector widget.
Similar to combo-box, but displays all options in a single row of buttons.
set_out_of_range(action='error')
Set behavior when out-of-range value is applied.
Can be "error" (raise error), "reset" (reset to no-value position), "reset_start" (reset to the first
position) or "ignore" (keep current value).
set_direct_index_action(action='error')
Set behavior when index values are specified, but direct indexing is used.
Can be "ignore" (do not allow direct indexing and treat any value as index value), "value_default"
(allow direct indexing, but prioritize index values with the same value), or "index_default" (allow
direct indexing and prioritize it if index value with the same value exists).
index_to_value(idx)
Turn numerical index into value
value_to_index(value)
Turn value into a numerical index
keep = keep
none = none
iterbuttons()
Iterate over all selecting buttons
set_buttons_width(width)
Set the fixed width of all the buttons
set_index_values(index_values, value=keep, index=None, unselected_value=keep)
Set a list of values corresponding to combo box indices.
Can be either a list of values, whose length must be equal to the number of options, or None (simply
use indices). Note: if the number of combo box options changed (e.g., using addItem or insertItem
methods), the index values need to be manually updated; otherwise, the errors might arise if the index is
larger than the number of values. If value is specified, set as the new values. If index is specified, use it as
the index of a new value; if both value and index are specified, the value takes priority. If unselected_value
is supplied, it specifies which value corresponds to no combo box value being selected (by default, keep
the current value).
get_index_values()
Return the list of values corresponding to combo box indices
get_options()
Return the list of labels corresponding to combo box indices
get_options_dict()
Return the dictionary {value: label} of the option labels
set_options(options, index_values=None, value=keep, index=None, unselected_value=keep)
Set new set of options.
If index_values is not None, set these as the new index values; otherwise, index values are reset. If options
is a dictionary, interpret it as a mapping {option: index_value}. If value is specified, set as the new
values. If index is specified, use it as the index of a new value; if both value and index are specified, the
value takes priority. If unselected_value is supplied, it specifies which value corresponds to no combo box
value being selected (by default, keep the current value).
value_changed = <Mock name='mock.QtCore.pyqtSignal()' id='140527858977616'>
Signal emitted when value is changed
get_value()
Get current numerical value
set_value(value, notify_value_change=True)
Set current value.
If notify_value_change==True, emit the value_changed signal; otherwise, change value silently.
repr_value(value)
Return representation of value as a combo box text
pylablib.core.gui.widgets.combo_box module
class pylablib.core.gui.widgets.combo_box.ComboBox(parent)
Bases: object
Expanded combo box.
Maintains internally stored consistent value (which can be, e.g., accessed from different threads). Allows setting
values which are reported via value_changed signal instead of simple indices.
wheelEvent(event)
set_out_of_range(action='error')
Set behavior when out-of-range value is applied.
Can be "error" (raise error), "reset" (reset to no-value position), "reset_start" (reset to the first
position) or "ignore" (keep current value).
set_direct_index_action(action='error')
Set behavior when index values are specified, but direct indexing is used.
Can be "ignore" (do not allow direct indexing and treat any value as index value), "value_default"
(allow direct indexing, but prioritize index values with the same value), or "index_default" (allow
direct indexing and prioritize it if index value with the same value exists).
index_to_value(idx)
Turn numerical index into value
value_to_index(value)
Turn value into a numerical index
keep = keep
none = none
get_options()
Return the list of labels corresponding to combo box indices
get_options_dict()
Return the dictionary {value: label} of the option labels
set_options(options, index_values=None, value=None, index=None, unselected_value=keep)
Set new set of options.
If index_values is not None, set these as the new index values; otherwise, index values are reset. If options
is a dictionary, interpret it as a mapping {option: index_value}. If value is specified, set as the new
values. If index is specified, use it as the index of a new value; if both value and index are specified, the
value takes priority. If unselected_value is supplied, it specifies which value corresponds to no combo box
value being selected (by default, keep the current value).
insert_option(option, index_value=None, index=None)
Insert or append a new option to the list
Insertion (i.e., index is not None) only works for index-valued combo boxes.
value_changed = <Mock name='mock.QtCore.pyqtSignal()' id='140527858977616'>
Signal emitted when value is changed
get_value()
Get current numerical value
set_value(value, notify_value_change=True)
Set current value.
If notify_value_change==True, emit the value_changed signal; otherwise, change value silently.
repr_value(value)
Return representation of value as a combo box text
pylablib.core.gui.widgets.container module
period
timer
start
stop
timer
gui_values_path
name
widget
setup_name(name)
Set the object’s name
setup(name=None)
Setup the container by initializing its GUI values and setting the ctl attribute
add_timer(name, period, autostart=True)
Add a periodic timer with the given name and period.
Rarely needs to be called explicitly (one is created automatically if timer event is created). If
autostart==True and the container has been started (by calling start() method), start the timer as
well.
start_timer(name)
Start the timer with the given name (also called automatically on start() method)
stop_timer(name)
Stop the timer with the given name (also called automatically on stop() method)
is_timer_running(name)
Check if the timer with the given name is running
add_timer_event(name, loop=None, start=None, stop=None, period=None, timer=None, autostart=True)
Add timer event with the given name.
Add an event which should be called periodically (e.g., a GUI update). Internally implemented through Qt
timers. loop, start and stop are the functions called, correspondingly, on timer (periodically), when timer
is start, and when it’s finished. One can either specify the timer by name (timer parameter), or create a new
one with the given period. If autostart==True and the container has been started (by calling start()
method), start the timer as well.
add_child_values(name, widget, path, add_change_event=True)
Add child’s values to the container’s table.
If widget is a container and path=="" or ends in "/*" (e.g., "subpath/*"), use its setup_gui_values
to make it share the same GUI values; otherwise, simply add it to the GUI values under the
given path. if add_change_event==True, changing of the widget’s value emits the container’s
contained_value_changed event
add_child(name, widget, gui_values_path=True, add_change_event=True)
Add a contained child widget.
If gui_values_path is False or None, do not add it to the GUI values table; if it is True, add it under
the same root (path=="") if it’s a container, and under name if it’s not; otherwise, gui_values_path
specifies the path under which the widget values are stored. if add_change_event==True, changing of
the widget’s value emits the container’s contained_value_changed event
get_child(name)
Get the child widget with the given name
remove_child(name, clear=True)
Remove child from the container and (if clear==True) clear it
add_virtual_element(name, value=None, multivalued=False, add_indicator=True)
Add a virtual value element.
Doesn’t correspond to any actual widget, but behaves very similarly from the application point of view (its
value can be set or read, it has on-change events, it can have indicator). The element value is simply stored
on set and retrieved on get. If multivalued==True, the internal value is assumed to be complex, so it is
forced to be a Dictionary every time it is set. If add_indicator==True, add default indicator handler
as well.
add_property_element(name, getter=None, setter=None, add_indicator=True)
Add a property value element.
Doesn’t correspond to any actual widget, but behaves very similarly from the application point of
view; each time the value is set or get, the corresponding setter and getter methods are called. If
add_indicator==True, add default (stored value) indicator handler as well.
start()
Start the container.
Starts all the internal timers, and calls start method for all the contained widgets.
stop()
Stop the container.
Stops all the internal timers, and calls stop method for all the contained widgets.
is_running()
Check if the container is running (started and not yet stopped)
is_stopping()
Check if the container is stopping (stopping initialized and not yet done)
clear()
Clear the container.
Stop all timers and widgets, and call clear methods of all contained widgets, remove all widgets from the
values table, remove all widgets from the table.
get_handler(name)
Get value handler of a widget with the given name
get_widget(name)
Get a widget corresponding to a value with the given name
get_value(name=None)
Get value of a widget with the given name (None means all values)
get_all_values()
Get values of all widget in the container
set_value(name, value)
Set value of a widget with the given name (None means all values)
set_all_values(value)
Set values of all widgets in the container
get_value_changed_signal(name)
Get a value-changed signal for a widget with the given name
update_value(name=None)
Send update signal for a handler with a given name or list of names.
Emit a value changed signal with the current value to notify the subscribed slots. If name is None, emit
for all values in the table.
get_indicator(name=None)
Get indicator value for a widget with the given name (None means all indicators)
get_all_indicators()
Get indicator values of all widget in the container
set_indicator(name, value, ignore_missing=False)
Set indicator value for a widget or a branch with the given name
set_all_indicators(value, ignore_missing=True)
update_indicators()
Update all indicators to represent current values
class pylablib.core.gui.widgets.container.QContainer(*args, name=None, **kwargs)
Bases: IQContainer, object
Basic controller object which combines and controls several other widget.
Can either corresponds to a widget (e.g., a frame or a group box), or simply be an organizing entity.
Parameters
name – entity name (used by default when adding this object to a values table)
Simply a combination of IQContainer and QObject.
TimerUIDGenerator = <pylablib.core.utils.general.NamedUIDGenerator object>
get_all_indicators()
Get indicator values of all widget in the container
get_all_values()
Get values of all widget in the container
get_child(name)
Get the child widget with the given name
get_handler(name)
Get value handler of a widget with the given name
get_indicator(name=None)
Get indicator value for a widget with the given name (None means all indicators)
get_value(name=None)
Get value of a widget with the given name (None means all values)
get_value_changed_signal(name)
Get a value-changed signal for a widget with the given name
get_widget(name)
Get a widget corresponding to a value with the given name
is_running()
Check if the container is running (started and not yet stopped)
is_stopping()
Check if the container is stopping (stopping initialized and not yet done)
is_timer_running(name)
Check if the timer with the given name is running
remove_child(name, clear=True)
Remove child from the container and (if clear==True) clear it
set_all_indicators(value, ignore_missing=True)
set_all_values(value)
Set values of all widgets in the container
set_indicator(name, value, ignore_missing=False)
Set indicator value for a widget or a branch with the given name
set_value(name, value)
Set value of a widget with the given name (None means all values)
setup(name=None)
Setup the container by initializing its GUI values and setting the ctl attribute
setup_name(name)
Set the object’s name
start()
Start the container.
Starts all the internal timers, and calls start method for all the contained widgets.
start_timer(name)
Start the timer with the given name (also called automatically on start() method)
stop()
Stop the container.
Stops all the internal timers, and calls stop method for all the contained widgets.
stop_timer(name)
Stop the timer with the given name (also called automatically on stop() method)
update_indicators()
Update all indicators to represent current values
update_value(name=None)
Send update signal for a handler with a given name or list of names.
Emit a value changed signal with the current value to notify the subscribed slots. If name is None, emit
for all values in the table.
class pylablib.core.gui.widgets.container.IQWidgetContainer(*args, **kwargs)
Bases: IQLayoutManagedWidget, IQContainer
Generic widget container.
Combines IQContainer management of GUI values and timers with IQLayoutManagedWidget management
of the contained widget’s layout.
Typically, adding widget adds them both to the container values and to the layout; however, this can be
skipped by either using QLayoutManagedWidget.add_to_layout() (only add to the layout), or specifying
location="skip" in add_child() (only add to the container).
Abstract mix-in class, which needs to be added to a class inheriting from QWidget. Alternatively, one can directly
use QWidgetContainer, which already inherits from QWidget.
setup(layout='vbox', no_margins=False, name=None)
Setup the layout.
Parameters
• layout – layout kind; can be "grid", "vbox" (vertical single-column box), or
"hbox" (horizontal single-row box).
• no_margins – if True, set all layout margins to zero (useful when the widget is in the
middle of layout hierarchy)
add_child(name, widget, location=None, gui_values_path=True)
Add a contained child widget.
name specifies the child storage name; if name==False, only add the widget to they layout, but not to the
container. location specifies the layout location to which the widget is added; if location=="skip", skip
adding it to the layout (can be manually added later). Note that if the widget is added to the layout, it will
be completely deleted when clear or remove_child methods are called; otherwise, simply its clear
method will be called, and its GUI values will be deleted.
If gui_values_path is False or None, do not add it to the GUI values table; if it is True, add it under
the same root (path=="") if it’s a container, and under name if it’s not; otherwise, gui_values_path
specifies the path under which the widget values are stored.
remove_child(name, clear=True)
Remove widget from the container and the layout and (if clear==True) clear it, and remove it
add_frame(name, layout='vbox', location=None, gui_values_path=True, no_margins=True)
Add a new frame container to the layout.
layout specifies the layout ("vbox", "hbox", or "grid") of the new frame, and location specifies its
location within the container layout. If no_margins==True, the frame will have no inner layout margins.
The other parameters are the same as in add_child() method.