Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

Using Continuous Sampling in NI DAQmx, using Python, with NI USB-6251 DAQ board

Hey everyone,

 

I am trying to set up a Read function on an Analog Input pin, in a loop, with the goal of being able to collect and handle pseudo-continuous data for an 8-hour period (overnight). To do this, my current code is the following: 

from PyDAQmx import *
import numpy
from ctypes import *
import matplotlib.pyplot as plt
import time

# Example from https://pythonhosted.org/PyDAQmx/usage.html to develop understanding

# Declaration of variable passed by reference
taskHandle = TaskHandle()
read = int32()
samples = 1000000       # 1 full second of data
num_secs = 5
data_sec = numpy.ndarray((samples,), dtype=numpy.float64)
data_bulk = []
pulseAmpAvg = []
pulseWidths = []

#DAQmx Configure Code
DAQmxCreateTask(b'', byref(taskHandle))

DAQmxCreateAIVoltageChan(taskHandle,             #Handle of task to associate voltage channel 
                         b'Dev1/ai0',            #Name of physical channel to be used (Device 1, Analog Input 0)
                         b'',                    #Name to associate with newly associated channel
                         DAQmx_Val_Diff,         #Configuration of channel
                         -10,                    #Minimum expected measurement (in units)
                         10,                     #Maximum expected measurement (in units)
                         DAQmx_Val_Volts,        #Defines units, in this case Volts
                         None)                   #Name of custom scale to apply, must be null if "units" set to Volts

DAQmxCfgSampClkTiming(taskHandle,                #Handle of task to associate sampling info
                      b'',                       #Source terminal of samp clock. To use device internal clock, use NULL
                      1000000.0,                 #Sampling rate in samples/sec/channel
                      DAQmx_Val_Rising,          #Specifies clock edge to acquire samples
                      DAQmx_Val_ContSamps,     #Defines continuous or finite operation of task
                      samples)                   #Number of samples to acquire

DAQmxCfgInputBuffer(taskHandle,                  #Overrides automatic buffer creation
                    samples)                     #Size of input buffer to be created, in samples

#    DAQmxCfgAnlgEdgeRefTrig(taskHandle,              #Handle of task to associate trigger
#                            b'Dev1/ai0',             #Selected channel for measurement
#                            DAQmx_Val_RisingSlope,  #Slope of signal on which trigger should occur
#                            2,                      # Trigger reference voltage
#                            3)                       # Number of pretrigger samples to collect



for i in range(1, num_secs):
    #DAQmx Start Code
    DAQmxStartTask(taskHandle)
    
    #DAQmx Read Code
    DAQmxReadAnalogF64(taskHandle,                   #Handle of task whose data will be read
                       samples,                      #Number of samples per channel to read
                       10.0,                         #Timeout limit in seconds
                       DAQmx_Val_GroupByChannel,     #Specifies whether samples are interleaved
                       data_sec,                         #Size of the array into which samples are read
                       samples,                      #Reserved for future use, pass NULL
                       byref(read),                  #Array to read samples into
                       None)                         #Actual number of samples read from each channel (in this example, don't care)
    
    data_bulk.append(data_sec)
    
    DAQmxStopTask(taskHandle)
    
#print ("Acquired %d points"%read.value)

pulseCount = 0
pulseInt = 0.0
dataInPulse = 0         # Boolean switch to identify pulse falling edge manually, distinguish between pulses

# Summing samples from pulse for later averaging
for data_sec in data_bulk:
    for i in data_sec:
        if i > 1:
            dataInPulse = 1
            pulseInt += i
            pulseCount += 1
        elif (dataInPulse and i < 1):
            pulseAmpAvg.append(pulseInt/pulseCount)
            pulseWidths.append(pulseCount)
            pulseInt = 0
            pulseCount = 0
            dataInPulse = 0     # Ensures that further non-pulse data points won't add to pulseAmpAvg array

if taskHandle:
    # DAQmx Stop code 
    DAQmxClearTask(taskHandle)

print('Average Pulse Amplitudes:')
print(pulseAmpAvg)
print('Pulse Widths (in us):')
print(pulseWidths)
plt.hist(pulseAmpAvg,
         bins = 10,
         density = True,
         stacked = False,
         edgecolor = "#666666",
         color = "#808080")
plt.hist(pulseWidths,
         bins = 10,
         density = True,
         stacked = False,
         edgecolor = "#666666",
         color = "#808080")
plt.show()

At present, I have StartTask and StopTask inside the for loop, which I know is incorrect. Originally I had only the Read function and some brief data handling within the for loop, but I generated Error 50103 (Attempting to use reserved resources). This makes it seem like I will need to run all of the task creation and clearing functions within the loop, but this will greatly reduce the amount of data within the 8-hour period that I will have access to, due to the large increase in overhead. The only solutions to this problem that I've seen have been in LabView, so I'd appreciate any advice on making this collect the data as efficiently as possible. It doesn't have to be able to read ALL of the values placed in the internal buffer during the 8-hour period, but I'd like to get as close as possible to that ideal.

 

Thanks in advance for the help!

0 Kudos
Message 1 of 2
(4,979 Views)

I still don't speak python and the call to DAQmxReadAnalogF64 still has some (but not all) of the questionable appearance I mentioned in an earlier thread.  If the argument variables are now known to be correct, you should update the comments to avoid confusion.

 

That said, I think the more immediate problem here is attempting to read the entire buffer all at once in a high-rate continuous task.  At most, I might plan to read 1/2.  A more common approach is to read about 1/10 sec worth of data per iteration.   Frankly, I'm pretty surprised you haven't gotten buffer overflow errors.

 

My advice: get the Start and Stop out of the loop.  Just iterate over reading.  Read 100k or 200k samples per iteration.  I don't know what "data_bulk.append()" does, but it could become a speed-limiting factor after a while.

 

 

-Kevin P

ALERT! LabVIEW's subscription-only policy came to an end (finally!). Unfortunately, pricing favors the captured and committed over new adopters -- so tread carefully.
0 Kudos
Message 2 of 2
(4,961 Views)