Skip to content

ni/nidaqmx-python

Repository files navigation

Info Contains a Python API for interacting with NI-DAQmx. See GitHub for the latest source.
Author National Instruments

About

The nidaqmx package contains an API (Application Programming Interface) for interacting with the NI-DAQmx driver. The package is implemented in Python. The package is implemented as a complex, highly object-oriented wrapper around the NI-DAQmx C API using the ctypes Python library.

nidaqmx supports all versions of the NI-DAQmx driver that ships with the C API. The C API is included in any version of the driver that supports it. The nidaqmx package does not require installation of the C header files.

Some functions in the nidaqmx package may be unavailable with earlier versions of the NI-DAQmx driver. Visit the ni.com/downloads to upgrade your version of NI-DAQmx.

nidaqmx supports Windows and Linux operating systems where the NI-DAQmx driver is supported. Refer to NI Hardware and Operating System Compatibility for which versions of the driver support your hardware on a given operating system.

nidaqmx supports CPython 3.8+ and PyPy3.

Installation

Running nidaqmx requires NI-DAQmx to be installed. Visit ni.com/downloads to download the latest version of NI-DAQmx. None of the recommended Additional items are required for nidaqmx to function, and they can be removed to minimize installation size. It is recommended you continue to install the NI Certificates package to allow your Operating System to trust NI built binaries, improving your software and hardware installation experience.

nidaqmx can be installed with pip:

$ python -m pip install nidaqmx

Similar Packages

There are similar packages available that also provide NI-DAQmx functionality in Python:

Getting Started

In order to use the nidaqmx package, you must have at least one DAQ (Data Acquisition) device installed on your system. Both physical and simulated devices are supported. The examples below use an X Series DAQ device (e.g.: PXIe-6363, PCIe-6363, or USB-6363). You can use NI MAX or NI Hardware Configuration Utility to verify and configure your devices.

Finding and configuring device name in NI MAX:

NI MAX Device Name

Finding and configuring device name in NI Hardware Configuration Utility:

NI HWCU Device Name

Tasks in NI-DAQmx

A task is a collection of one or more virtual channels with timing, triggering, and other properties. Refer to NI-DAQmx Task for more information.

Example code to create a task:

>>> import nidaqmx
>>> with nidaqmx.Task() as task:
...     pass

Virtual Channels in NI-DAQmx

Virtual channels, or sometimes referred to generically as channels, are software entities that encapsulate the physical channel along with other channel specific information (e.g.: range, terminal configuration, and custom scaling) that formats the data. A physical channel is a terminal or pin at which you can measure or generate an analog or digital signal. A single physical channel can include more than one terminal, as in the case of a differential analog input channel or a digital port of eight lines. Every physical channel on a device has a unique name (for instance, cDAQ1Mod4/ai0, Dev2/ao5, and Dev6/ctr3) that follows the NI-DAQmx physical channel naming convention. Refer to NI-DAQmx Channel for more information.

Example code that adds an analog input channel to a task, configures the range, and reads data:

>>> import nidaqmx
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0", min_val=-10.0, max_val=10.0)
...     task.read()
...
AIChannel(name=Dev1/ai0)
-0.14954069643238624

Example code that adds multiple analog input channels to a task, configures their range, and reads data:

>>> import nidaqmx
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0", min_val=-5.0, max_val=5.0)
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai1", min_val=-10.0, max_val=10.0)
...     task.read()
...
AIChannel(name=Dev1/ai0)
AIChannel(name=Dev1/ai1)
[-0.07477034821619312, 0.8642841883602405]

Timing

You can use software timing or hardware timing to control when a signal is acquired or generated. With hardware timing, a digital signal, such as a clock on your device, controls the rate of acquisition or generation. With software timing, the rate at which the samples are acquired or generated is determined by the software and operating system instead of by the measurement device. A hardware clock can run much faster than a software loop. A hardware clock is also more accurate than a software loop. Refer to Timing, Hardware Versus Software for more information.

Example code to acquire finite amount of data using hardware timing:

>>> import nidaqmx
>>> from nidaqmx.constants import AcquisitionType, READ_ALL_AVAILABLE
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
...     task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=10)
...     data = task.read(READ_ALL_AVAILABLE)
...     print("Acquired data: [" + ", ".join(f"{value:f}" for value in data) + "]")
...
AIChannel(name=Dev1/ai0)
Acquired data: [-0.149693, 2.869503, 4.520249, 4.704886, 2.875912, -0.006104, -2.895596, -4.493698, -4.515671, -2.776574]

TDMS Logging

Technical Data Management Streaming (TDMS) is a binary file format that allows for high-speed data logging. When you enable TDMS data logging, NI-DAQmx can stream data directly from the device buffer to the hard disk. Refer to TDMS Logging for more information.

Example code to acquire finite amount of data and log it to a TDMS file:

>>> import nidaqmx
>>> from nidaqmx.constants import AcquisitionType, LoggingMode, LoggingOperation, READ_ALL_AVAILABLE
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
...     task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=10)
...     task.in_stream.configure_logging("TestData.tdms", LoggingMode.LOG_AND_READ, operation=LoggingOperation.CREATE_OR_REPLACE)
...     data = task.read(READ_ALL_AVAILABLE)
...     print("Acquired data: [" + ", ".join(f"{value:f}" for value in data) + "]")
...
AIChannel(name=Dev1/ai0)
Acquired data: [-0.149693, 2.869503, 4.520249, 4.704886, 2.875912, -0.006104, -2.895596, -4.493698, -4.515671, -2.776574]

To read the TDMS file, you can use the npTDMS third-party module. Refer to npTDMS for detailed usage.

Example code to read the TDMS file created from example above and display the data:

>>> from nptdms import TdmsFile
>>> with TdmsFile.read("TestData.tdms") as tdms_file:
...   for group in tdms_file.groups():
...     for channel in group.channels():
...       data = channel[:]
...       print("data: [" + ", ".join(f"{value:f}" for value in data) + "]")
...
data: [-0.149693, 2.869503, 4.520249, 4.704886, 2.875912, -0.006104, -2.895596, -4.493698, -4.515671, -2.776574]

Plot Data

To visualize the acquired data as a waveform, you can use the matplotlib.pyplot third-party module. Refer to Pyplot tutorial for detailed usage.

Example code to plot waveform for acquired data using matplotlib.pyplot module:

>>> import nidaqmx
>>> from nidaqmx.constants import AcquisitionType, READ_ALL_AVAILABLE
>>> import matplotlib.pyplot as plt
>>> with nidaqmx.Task() as task:
...   task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
...   task.timing.cfg_samp_clk_timing(1000.0, sample_mode=AcquisitionType.FINITE, samps_per_chan=50)
...   data = task.read(READ_ALL_AVAILABLE)
...   plt.plot(data)
...   plt.ylabel('Amplitude')
...   plt.title('Waveform')
...   plt.show()
...
AIChannel(name=Dev1/ai0)
[<matplotlib.lines.Line2D object at 0x00000141D7043970>]
Text(0, 0.5, 'Amplitude')
Text(0.5, 1.0, 'waveform')

Waveform

For more information on how to use nidaqmx package, refer to Usage section below.

Usage

The following is a basic example of using an nidaqmx.task.Task object. This example illustrates how the single, dynamic nidaqmx.task.Task.read method returns the appropriate data type.

>>> import nidaqmx
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
...     task.read()
...
-0.07476920729381246
>>> with nidaqmx.Task() as task:
...     task.ai_channels.add_ai_voltage_chan("Dev1/ai0")
...     task.read(number_of_samples_per_channel=2)
...
[0.26001373311970705, 0.37796597238117036]
>>> from nidaqmx.constants import LineGrouping
>>> with nidaqmx.Task() as task:
...     task.di_channels.add_di_chan(
...         "cDAQ2Mod4/port0/line0:1", line_grouping=LineGrouping.CHAN_PER_LINE)
...     task.read(number_of_samples_per_channel=2)
...
[[False, True], [True, True]]

A single, dynamic nidaqmx.task.Task.write method also exists.

>>> import nidaqmx
>>> from nidaqmx.types import CtrTime
>>> with nidaqmx.Task() as task:
...     task.co_channels.add_co_pulse_chan_time("Dev1/ctr0")
...     sample = CtrTime(high_time=0.001, low_time=0.001)
...     task.write(sample)
...
1
>>> with nidaqmx.Task() as task:
...     task.ao_channels.add_ao_voltage_chan("Dev1/ao0")
...     task.write([1.1, 2.2, 3.3, 4.4, 5.5], auto_start=True)
...
5

Consider using the nidaqmx.stream_readers and nidaqmx.stream_writers classes to increase the performance of your application, which accept pre-allocated NumPy arrays.

Following is an example of using an nidaqmx.system.System object.

>>> import nidaqmx.system
>>> system = nidaqmx.system.System.local()
>>> system.driver_version
DriverVersion(major_version=16L, minor_version=0L, update_version=0L)
>>> for device in system.devices:
...     print(device)
...
Device(name=Dev1)
Device(name=Dev2)
Device(name=cDAQ1)
>>> import collections
>>> isinstance(system.devices, collections.Sequence)
True
>>> device = system.devices['Dev1']
>>> device == nidaqmx.system.Device('Dev1')
True
>>> isinstance(device.ai_physical_chans, collections.Sequence)
True
>>> phys_chan = device.ai_physical_chans['ai0']
>>> phys_chan
PhysicalChannel(name=Dev1/ai0)
>>> phys_chan == nidaqmx.system.PhysicalChannel('Dev1/ai0')
True
>>> phys_chan.ai_term_cfgs
[<TerminalConfiguration.RSE: 10083>, <TerminalConfiguration.NRSE: 10078>, <TerminalConfiguration.DIFFERENTIAL: 10106>]
>>> from enum import Enum
>>> isinstance(phys_chan.ai_term_cfgs[0], Enum)
True

You can find more examples in nidaqmx-python examples.

Bugs / Feature Requests

To report a bug or submit a feature request, please use the GitHub issues page.

Information to Include When Asking for Help

Please include all of the following information when opening an issue:

  • Detailed steps on how to reproduce the problem and full traceback, if applicable.

  • The python version used:

    $ python -c "import sys; print(sys.version)"
    
  • The versions of the nidaqmx and numpy packages used:

    $ python -m pip list
    
  • The version of the NI-DAQmx driver used. Follow this KB article to determine the version of NI-DAQmx you have installed.

  • The operating system and version, for example Windows 7, CentOS 7.2, ...

Documentation

Documentation is available here.

Additional Documentation

Refer to the NI-DAQmx Help for API-agnostic information about NI-DAQmx or measurement concepts.

NI-DAQmx Help installs only with the full version of NI-DAQmx.

License

nidaqmx is licensed under an MIT-style license (see LICENSE). Other incorporated projects may be licensed under different licenses. All licenses allow for non-commercial and commercial use.

gRPC Features For driver APIs that support it, passing a GrpcSessionOptions instance as a parameter is subject to the NI General Purpose EULA (see NILICENSE).