NI DAQs¶
This module has been developed using an NI USB-6221 – the code should generally work for all DAQmx boards, but I’m sure there are plenty of compatibility bugs just waiting for you wonderful users to find and fix.
First, make sure you have NI’s DAQmx software installed. Once that’s set, you’ll need PyDAQmx, a basic Python interface to DAQmx. You can get it via pip:
pip install PyDAQmx
The NIDAQ
class lets you interact with your board and all its various inputs
and outputs in a fairly simple way. Let’s say you’ve hooked up digital I/O P1.0
to analog input AI0, and your analog out AO1 to analog input AI1:
>>> from instrumental.drivers.daq.ni import NIDAQ, list_instruments
>>> list_instruments()
[<NIDAQ 'Dev0'>]
>>> daq = NIDAQ('Dev0')
>>> daq.ai0.read()
<Quantity(0.0154385786803, 'volt)>
>>> daq.port1[0].write(True)
>>> daq.ai0.read()
<Quantity(5.04241962841, 'volt')>
>>> daq.ao1.write('2.1V')
>>> daq.ai1.read()
<Quantity(2.10033320744, 'volt')>
Now let’s try using digital input. Assume P1.1 is attached to P1.2:
>>> daq.port1[1].write(False)
>>> daq.port1[2].read()
False
>>> daq.port1[1].write(True)
>>> daq.port1[2].read()
True
Let’s read and write more than one bit at a time. To write to multiple lines
simultaneously, pass an unsigned int to write()
. The line with the lowest
index corresponds to the lowest bit, and so on. If you read from multiple
lines, read() returns an int. Connect P1.0-3 to P1.4-7:
>>> daq.port1[0:3].write(5) # 0101 = decimal 5
>>> daq.port1[4:7].read() # Note that the last index IS included
5
>>> daq.port1[7:4].read() # This flips the ordering of the bits
10 # 1010 = decimal 10
>>> daq.port1[0].write(False) # Zero the ones bit individually
>>> daq.port1[4:7].read() # 0100 = decimal 4
4
You can also read and write arrays of buffered data. Use the same read()
and
write()
methods, just include your timing info (and pass in the data as an
array if writing). When writing, you must provide either freq
or fsamp
, and
may provide either duration
or reps
to specify for how long the waveform is
output. For example, there are many ways to output the same sinusoid:
>>> from instrumental import u
>>> from numpy import pi, sin, linspace
>>> data = sin( 2*pi * linspace(0, 1, 100, endpoint=False) )*5*u.V + 5*u.V
>>> daq.ao0.write(data, duration='1s', freq='500Hz')
>>> daq.ao0.write(data, duration='1s', fsamp='50kHz')
>>> daq.ao0.write(data, reps=500, freq='500Hz')
>>> daq.ao0.write(data, reps=500, fsamp='50kHz')
Note the use of endpoint=False
in linspace
. This ensures we don’t
repeat the start/end point (0V) of our sine waveform when outputting more than
one period.
All this stuff is great for simple tasks, but sometimes you may want to perform input and output on multiple channels simultaneously. To accomplish this we need to use Tasks.
Note
Tasks in the ni
module are similar, but not the same as Tasks in DAQmx
(and PyDAQmx). Our Tasks allow you to quickly and easily perform simultaneous
input and output with one Task without the hassle of having to create multiple
and hook their timing and triggers up.
Here’s an example of how to perform simultaneous input and output:
>>> from instrumental.drivers.daq.ni import NIDAQ, Task
>>> from instrumental import u
>>> from numpy import linspace
>>> daq = NIDAQ('Dev0')
>>> task = Task(daq.ao0, daq.ai0)
>>> task.set_timing(duration='1s', fsamp='10Hz')
>>> write_data = {'ao0': linspace(0, 9, 10) * u.V}
>>> task.run(write_data)
{u'ai0': <Quantity([ 1.00000094e+01 1.89578724e-04 9.99485542e-01 2.00007917e+00
3.00034866e+00 3.99964556e+00 4.99991698e+00 5.99954114e+00
6.99981625e+00 7.99976941e+00], 'volt')>,
u't': <Quantity([ 0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9], 'second')>}
As you can see, we create a dict as input to the run()
method. Its keys are
the names of the input channels, and its values are the corresponding array
Quantities that we want to write. Similarly, the run()
returns a dict that
contains the input that was read. This dict also contains the time data under
key ‘t’. Note that the read and write happen concurrently, so each voltage read
has not yet moved to its new setpoint.
Module Reference¶
Driver module for NI-DAQmx-supported hardware.
-
class
instrumental.drivers.daq.ni.
AnalogIn
(dev, chan_name)¶ Methods
read
([duration, fsamp, n_samples])Read one or more analog input samples. -
__init__
(dev, chan_name)¶
-
read
(duration=None, fsamp=None, n_samples=None)¶ Read one or more analog input samples.
By default, reads and returns a single sample. If two of
duration
,fsamp
, andn_samples
are given, an array of samples is read and returned.Parameters: duration : Quantity
How long to read from the analog input, specified as a Quantity. Use with
fsamp
orn_samples
.fsamp : Quantity
The sample frequency, specified as a Quantity. Use with
duration
orn_samples
.n_samples : int
The number of samples to read. Use with
duration
orfsamp
.Returns: data : scalar or array Quantity
The data that was read from analog input.
-
-
class
instrumental.drivers.daq.ni.
AnalogOut
(dev, chan_name)¶ Methods
write
(data[, duration, reps, fsamp, freq, ...])Write a value or array to the analog output. -
__init__
(dev, chan_name)¶
-
write
(data, duration=None, reps=None, fsamp=None, freq=None, onboard=True)¶ Write a value or array to the analog output.
If
data
is a scalar value, it is written to output and the function returns immediately. Ifdata
is an array of values, a buffered write is performed, writing each value in sequence at the rate determined byduration
andfsamp
orfreq
. You must specify eitherfsamp
orfreq
.When writing an array, this function blocks until the output sequence has completed.
Parameters: data : scalar or array Quantity
The value or values to output, passed in Volt-compatible units.
duration : Quantity, optional
Used when writing arrays of data. This is how long the entirety of the output lasts, specified as a second-compatible Quantity. If
duration
is longer than a single period of data, the waveform will repeat. Use either this orreps
, not both. If neither is given, waveform is output once.reps : int or float, optional
Used when writing arrays of data. This is how many times the waveform is repeated. Use either this or
duration
, not both. If neither is given, waveform is output once.fsamp: Quantity, optional
Used when writing arrays of data. This is the sample frequency, specified as a Hz-compatible Quantity. Use either this or
freq
, not both.freq : Quantity, optional
Used when writing arrays of data. This is the frequency of the overall waveform, specified as a Hz-compatible Quantity. Use either this or
fsamp
, not both.onboard : bool, optional
Use only onboard memory. Defaults to True. If False, all data will be continually buffered from the PC memory, even if it is only repeating a small number of samples many times.
-
-
class
instrumental.drivers.daq.ni.
Channel
¶
-
class
instrumental.drivers.daq.ni.
Counter
(dev, chan_name)¶ Methods
output_pulses
(freq[, duration, reps, ...])Generate digital pulses using the counter. -
__init__
(dev, chan_name)¶
-
output_pulses
(freq, duration=None, reps=None, idle_high=False, delay=None, duty_cycle=0.5)¶ Generate digital pulses using the counter.
Outputs digital pulses with a given frequency and duty cycle.
This function blocks until the output sequence has completed.
Parameters: freq : Quantity
This is the frequency of the pulses, specified as a Hz-compatible Quantity.
duration : Quantity, optional
How long the entirety of the output lasts, specified as a second-compatible Quantity. Use either this or
reps
, not both. If neither is given, only one pulse is generated.reps : int, optional
How many pulses to generate. Use either this or
duration
, not both. If neither is given, only one pulse is generated.idle_high : bool, optional
Whether the resting state is considered high or low. Idles low by default.
delay : Quantity, optional
How long to wait before generating the first pulse, specified as a second-compatible Quantity. Defaults to zero.
duty_cycle : float, optional
The width of the pulse divided by the pulse period. The default is a 50% duty cycle.
-
-
class
instrumental.drivers.daq.ni.
NIDAQ
(dev_name)¶ Methods
create_task
()get_AI_channels
()get_AI_max_range
()Returns the min and max voltage of the widest AI range get_AI_ranges
()get_AO_channels
()get_AO_max_range
()Returns the min and max voltage of the widest AO range get_AO_ranges
()get_CI_channels
()get_CO_channels
()get_DI_lines
()get_DI_ports
()get_DO_lines
()get_DO_ports
()get_chassis_num
()get_product_type
()get_serial
()get_slot_num
()get_terminals
()-
__init__
(dev_name)¶ Constructor for an NIDAQ object. End users should not use this directly, and should instead use
instrument()
-
create_task
()¶
-
get_AI_channels
()¶
-
get_AI_max_range
()¶ Returns the min and max voltage of the widest AI range
-
get_AI_ranges
()¶
-
get_AO_channels
()¶
-
get_AO_max_range
()¶ Returns the min and max voltage of the widest AO range
-
get_AO_ranges
()¶
-
get_CI_channels
()¶
-
get_CO_channels
()¶
-
get_DI_lines
()¶
-
get_DI_ports
()¶
-
get_DO_lines
()¶
-
get_DO_ports
()¶
-
get_chassis_num
()¶
-
get_product_type
()¶
-
get_serial
()¶
-
get_slot_num
()¶
-
get_terminals
()¶
-
-
class
instrumental.drivers.daq.ni.
Task
(*args)¶ Note that true DAQmx tasks can only include one type of channel (e.g. AI). To run multiple synchronized reads/writes, we need to make one task for each type, then use the same sample clock for each.
Methods
run
([write_data])set_timing
([duration, fsamp, n_samples, ...])-
__init__
(*args)¶ Creates a task that uses the given channels.
Each arg can either be a Channel or a tuple of (Channel, name_str)
-
run
(write_data=None)¶
-
set_timing
(duration=None, fsamp=None, n_samples=None, mode=u'finite', clock=u'', rising=True)¶
-
-
class
instrumental.drivers.daq.ni.
VirtualDigitalChannel
(dev, line_pairs)¶ Methods
as_input
()as_output
()read
()write
(value)Write a value to the digital output channel write_sequence
(data[, duration, reps, ...])Write an array of samples to the digital output channel -
__init__
(dev, line_pairs)¶
-
as_input
()¶
-
as_output
()¶
-
read
()¶
-
write
(value)¶ Write a value to the digital output channel
Parameters: value : int or bool
An int representing the digital values to write. The lowest bit of the int is written to the first digital line, the second to the second, and so forth. For a single-line DO channel, can be a bool.
-
write_sequence
(data, duration=None, reps=None, fsamp=None, freq=None, onboard=True)¶ Write an array of samples to the digital output channel
Outputs a buffered digital waveform, writing each value in sequence at the rate determined by
duration
andfsamp
orfreq
. You must specify eitherfsamp
orfreq
.This function blocks until the output sequence has completed.
Parameters: data : array or list of ints or bools
The sequence of samples to output. For a single-line DO channel, samples can be bools.
duration : Quantity, optional
How long the entirety of the output lasts, specified as a second-compatible Quantity. If
duration
is longer than a single period of data, the waveform will repeat. Use either this orreps
, not both. If neither is given, waveform is output once.reps : int or float, optional
How many times the waveform is repeated. Use either this or
duration
, not both. If neither is given, waveform is output once.fsamp: Quantity, optional
This is the sample frequency, specified as a Hz-compatible Quantity. Use either this or
freq
, not both.freq : Quantity, optional
This is the frequency of the overall waveform, specified as a Hz-compatible Quantity. Use either this or
fsamp
, not both.onboard : bool, optional
Use only onboard memory. Defaults to True. If False, all data will be continually buffered from the PC memory, even if it is only repeating a small number of samples many times.
-
-
instrumental.drivers.daq.ni.
list_instruments
()¶