0

I am having trouble using Python and the nidaqmx library to properly to read N number of samples. I am using an NI USB-6366 daq. In short, my target is to get a signal of total N samples. Where there will be M pre-triggered samples and (N-M) post-triggered samples. The triggering will happen when the signal's amplitude crosses a threshold. And I am going to use a manual impact to excite incident waves. I am not using any other channel of the DAQ as a triggering source. Currently, I am trying this code:

def hardwareFiniteVoltage():
      import nidaqmx
      import numpy as np
      import matplotlib.pyplot as plt
      sampleRate = 2E5   # Sample Rate in Hz
      secsToAcquire = 1    # Number of seconds over which to acquire data
      numberOfSamples = int(secsToAcquire * sampleRate)
      print('Acquiring %d data points' % numberOfSamples)
      with nidaqmx.Task('hardwareFiniteVoltage') as task:
         task.ai_channels.add_ai_voltage_chan('Dev1/ai0')
         task.timing.cfg_samp_clk_timing(sampleRate,samps_per_chan=numberOfSamples, 
         sample_mode=nidaqmx.constants.AcquisitionType(10178))
         
         task.triggers.reference_trigger.cfg_anlg_edge_ref_trig(
         'Dev1/ai0',10000,trigger_level=0.1)

                                    
         task.start()
         data = task.read(number_of_samples_per_channel=numberOfSamples)
         plt.plot(data)
         plt.xlabel('time [samples]')
         plt.ylabel('voltage [V]')
         plt.grid()
         plt.show()



if __name__ == '__main__':
      hardwareFiniteVoltage()
Khan02
  • 1
  • 1

1 Answers1

0

I can't say if you can hardwarely do that, because I don't know the specific USB card, but I'm sure you can check the feasibility on the datasheet. As long as the python code is concerned, triggered acquisition must be done in an asynchronous approach: your acquisition function will be called by nidaqmx as soon as the data is available (i.e., N samples at the trigger event has happened).

Note:

  • As far as I understood from doc, cfg_anlg_edge_ref_trig makes nidaq provide you at least N samples BEFORE trigger happened: is really what you need or were you looking for N samples AFTER the trigger event?

    After a deeper investigation of the documentation, cfg_anlg_edge_ref_trig let you specify pretrigger_samples, i.e. the number of samples you acquire before the trigger. The number of samples acquired in POST-TRIGGER will result as the difference between numberOfSamples (the total number of samples specified in the call to task.timing.cfg_samp_clk_timing) and pretrigger_samples

Please check the doc for more info about the callback registration and for nidaq stram readers.

NOTE: The code is not tested since currently I have no nidaq card available. Sorry for the inconvenience

import nidaqmx
# This is an object that manage the samples stream acquisition
from nidaqmx import stream_readers
import numpy as np
import matplotlib.pyplot as plt
import time

# This var is initialized during task creation and is needed by your callback
nidaq_reader: stream_readers.AnalogMultiChannelReader = None


def do_something_with_data(data):
    # Just for convenience
    plt.plot(data)
    plt.xlabel('time [samples]')
    plt.ylabel('voltage [V]')
    plt.grid()
    plt.show()
    

def callback(task_handle, every_n_samples_event_type, number_of_samples, callback_data):
    try:
        # Allocate your numpy array (I'm assuming just one channel!)
        data = np.empty((number_of_samples,))
        # Now read the acquired samples
        number_of_samples_read = nidaq_reader.read_many_sample(data, number_of_samples)
    except Exception as e:
        print(f'Something went wrong reading samples: {e}')
    else:
        do_something_with_data(data)
    finally:
        # Always needed by nidaqmx to return 0!
        return 0

def hardwareFiniteVoltage():
      sampleRate = 2E5   # Sample Rate in Hz
      secsToAcquire = 1    # Number of seconds over which to acquire data
      numberOfSamples = int(secsToAcquire * sampleRate)
      
      pretrigger_samples = 10000
      print('Acquiring %d data points' % numberOfSamples)
      with nidaqmx.Task('hardwareFiniteVoltage') as task:
         task.ai_channels.add_ai_voltage_chan('Dev1/ai0')
         task.timing.cfg_samp_clk_timing(sampleRate,samps_per_chan=numberOfSamples, 
         sample_mode=nidaqmx.constants.AcquisitionType(10178))
         
         task.triggers.reference_trigger.cfg_anlg_edge_ref_trig(
         'Dev1/ai0',pretrigger_samples,trigger_level=0.1)
         
         # Here you register your callback into nidaqmx event loop
         task.register_every_n_samples_acquired_into_buffer_event(numberOfSamples, callback)
         
         # Initialize the stream_readers nidaq_reader to be used by your callback to get your actual data
         global nidaq_reader
         nidaq_reader = stream_readers.AnalogSingleChannelReader(task.in_stream)
                                    
         task.start()




if __name__ == '__main__':
      hardwareFiniteVoltage()
      
      while True:
        # Event loop. Don't use `pass`! It will saturate the CPU
        time.sleep(0.001)
Buzz
  • 1,102
  • 1
  • 9
  • 24
  • Hello, @Buzz thank you for your reply. Yes, you are right. I am trying to collect N samples after the trigger event and to collect m samples before the trigger event (pre-triggered data). Is the code you provided doing this? Can you please help me with the concept? what I need to do for starting to get a signal when the amplitude of the signal exceeds a threshold value – Khan02 Aug 20 '22 at 08:42
  • Not at all. My code was implementing only the callback call l, as I keep your trigger setup for granted. Yes, for sure, but I need some more time to check the doc. But please, edit your question to make it clearer what you're seeking – Buzz Aug 20 '22 at 09:06
  • Hi, thank you very much for your kind reply. I have edited my question. In short, my target is to get a signal of total N samples. Where there will be M pre-triggered samples and (N-M) post-triggered samples. The triggering will happen when the signal's amplitude crosses a threshold. And I am going to use a manual impact to excite incident waves. Can you please help me out? Thanks in advance. – Khan02 Aug 20 '22 at 09:26
  • I'm very sorry, I was wrong in understanding the documentation. The code was actually doing what you wanted, I've now corrected the note and made the code clearer. Sorry for the misunderstanding – Buzz Aug 20 '22 at 14:27