Data Acquistion Hints and Tips
A quick overview of how to structure your DACQ code and some other things to look out for.
Table of Contents
Please save your data!
If you analyse the data in the notebook in which it was acquired without saving it then you will be unable to analyse it on a different machine. To make even a minor change (e.g. adding a title to the graph) in the notebook in which it was acquired after a restart will require you to take the data again!
General DACQ program structure
While different experiments may have different data acquisition and control requirements, the general structre is pretty similar. Below is the outline of what a program to send out voltages (DACQ) and read back corresponding voltages (ADC) looks like.
- Load necessary libraries
- Define range(s) of interest (e.g. range of voltages to be sent out)
- Initialise and configure data acquisition interface.
- Initialise where data will be stored (e.g. lists) and other necessary variables
- Loop of range of interest:
- Write out voltage to DACQ
- Pause
- Read back corresponding voltage from ADC
- Append voltage from ADC to a list
- Plot data to see if everything looks good
- Save data and metadate to a file.
Example skeleton code:
Here is sample code do to this using the National Instrument USB 6008 where we send out some voltage and measure the corresponding current through a resistor.:
# Load standard libraries
import matplotlib.pyplot as plt
import numpy as np
from time import sleep
# Load NIDACQ libraries
from pydaqmx_helper.adc import ADC
from pydaqmx_helper.dac import DAC
# Define range of interest
voltages = np.linspace(0, +5, 50)
# Initialise DACQ interface:
myDAC = DAC(0)
myADC = ADC()
myADC.addChannels([1], minRange=0, maxRange=5)
# Initialse lists and other variables
R = 1_000 # 1 kOhm resistor use
delay_s = 0.1
currents = []
# Main DACQ loop:
for vout in voltages:
myDAC.writeVoltage(vout)
sleep(delay_s)
vin = myADC.readVoltage()
currents.append(vin/R)
# plot results
plt.plot(voltages, currents, "ro")
plt.title("I-V Curve of x")
plt.xlabel("Voltage (V)")
plt.xlabel("Current (A)")
# save data
filename = input("Please enter filename, blank to not save")
if filename:
np.savetxt(filename, np_c[voltages, currents],
header="Columns are Voltages (V) and Currents (I)")
DACQ things to look out for:
ADC range
When used in differential mode the USB 6008/6009 ADCs have programmable ranges which should be matched to the signal you are measuring. See the NI USB 6008/6009documentation
Sampling Voltages from one or more channels
If we need to take a lot of points quickly or with good timing or
readings from more than one channel then the National Instruments USB
6008/6009 have a sampleVoltages()
command where the module samples
at a give rate (10 kHz max for USB 6008) and returns all of the
values (i.e. yo do not need to do a loop but the downside is
that Python blocks while sampleVoltages() is active). See the NI USB 6008/6009 documentation
Checking for Errors
Some modules, such as the RBD 9103 Picoammeter may return unstable readings when they change ranges - make sure to check for instability and re-read if necessary.
Delays
You may pause your code using the sleep()
command from the time
library.
The sleeps are specified in seconds (floats - fractional seconds allowed).
from time import sleep
sleep(1.0)
High Performance timing
Python has high-performance timers for measuring small time intervals (useful for e.g. the Electrical Noise experiment for measuring the time between pulses). See: time.perf_counter() and time.perf_counter_ns()
Monitoring slow DACQ
If your DACQ code takes a long time to run because a lot of points are needed or large delays then it may be useful to monitor activity with a progress bar. See the HowTo on TQDM