LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Daqmx Signal Generation Drops Out

First off, this is my first post to the forums, and I only have less than a year of LV experience under my belt. 

 

For the last 8 months, I have been working on a project for my graduate education.  When I was given the code to modify it, it was essentially a AO voltage generator.  You could specify the device,  as well the frequency and amplitude of a sinusoid, that was sent to a shaker.  My assignment was to modify this to operate in a closed-loop system.  We read in two channels of data, compute features from the data, and, upon these features crossing certain thresholds, trigger sine wave generation to an AO port.  We also would like it to generate two digital outputs: one indicating detection (both threshold criterion are met), and one inidicating the state of a switch (which tells the VI to output the sine wave upon detection). 

 

The code as it is runs, but after several loop iterations ceases to output the signal from the AO. However, the sine wave itself is still being generated, leading me to believe its an issue with the DAQmx write/start task functions.  

 

I am relatively unfamiliar with the DAQmx functions, so any help, insights, or suggestions for improvement would be greatly appreciated.  You will find copies of the VI and subVI attached (sorry for it's lack of organization).  We are running the VI with a NI USB-6211.

 

 

 

Download All
0 Kudos
Message 1 of 5
(3,448 Views)

You've got a somewhat complex Control task here (possibly -- can't be sure I understand what you are attempting).  Before opening LabVIEW again, open Microsoft Word (or something similar) and write a document describing (to yourself, if noone else) precisely what you want to do.  You mention a shaker and accelerometer, but there are EMG and EEG channels in there, as well -- sounds very confusing, especially since EMG/EEG signal bandwidths are likely to be very different from a mechanical shaker and might thus warrant separate tasks/loops.

 

Try to find a local LabVIEW guru to help with coding and better LabVIEW Style.  Here are some suggestions that will improve your code.

 

  • You almost never need to use Frames (or Sequences).  You should definitely not use Stacked Frames.
  • Try to make all of your Block Diagrams fit on a single normal-size Display screen.  Usually this require "bundling" code into sub-VIs -- this is a very good thing to do.
  • Try to never use Express VIs -- they tend to "hide" important decisions that you should really make on your own.
  • Related to that, never use the Dynamic Data Type.  If you use "real" data wires (with arrays or quantities that you understand), you will be able to extract the data you want and need much more simply.
  • Take advantage of LabVIEW's ability to execute code in parallel.  Don't try to do everything all in a single loop, particularly if some elements need (or expect) precise timing.

Bob Schor

0 Kudos
Message 2 of 5
(3,432 Views)

Another thing -- if you go on NI's Support Web site (support.ni.com), you can find very helpful Tutorials and White Papers.  Click on Tutorials and start typing in the Search box "Learn 10 " and it should pop up a very helpful Tutorial on DAQmx.

 

BS

0 Kudos
Message 3 of 5
(3,428 Views)

Sorry, I was trying to spare you the pain of the details. I work in a Neural Engineering lab.  One of our major interests is sleep, and the roles it plays in things such as seizure occurance in Epileptic models of mice.  We implant mice with an EMG/EEG electrode, and monitor them via video recording and signal aquisition in Labview.  By computing features on these signals (i.e. Band Power), we can determine what state of sleep the animal is in.  

 

This VI is aimed to be used in a REM sleep restristion study.  In order to restrict mice of REM sleep, we are using a somatosensory stimulation, which is accomplished by a bass shaker mounted to the floor of the animals cage.  The idea is that upon entering REM sleep, the application of a mild vibration could cause the animal back into the previous sleep state.

 

The shaker is activated (through an analog sinusoidal voltage) via a function generated through an AO port on our 6211 box.  The amplitude and frequency of this sine wave is able to be controlled in the VI, to try to optimize restriction.  Stimulation is triggered when two criteria are met:

1) EMG power < EMG threshold (indicating the mouse is asleep)

and

2.) an EEG band-power ratio > EEG threshold.  

 

If the thresholds are not met, then we want to provide no stimulation (the false case of the case structure in which the sin wave is multiplied by 0).

 

In addition to reading EEG/EMG, we are also reading data from a piezo film on the floor of the cage, as well as an accelerometer (to confirm lack of movement in sleep and stimulation).

 

A boolean indicator ("Detection") is TRUE when both criteria are met, indicating theonset of REM sleep, during which we want to stimulate the animal.  However, stimulation is not allowed to occur unless a boolean control ("Stim Switch") is also true.  The state of "Detection" and "Stim Switch", both being binary, are then written to two digital outputs (via DAQ Assist for now).

 

The VI is proposed to work in the following flow:

1. Create 4 analog inputs(EEG, EMG, piezo, accelerometer) and 3 outputs (analog shaker out, digital detection out, and digital stim  switch out).

2. Filter the EMG/ EEG into desired frequency bands, compute the band-power, and compute features (i.e. EMG Power, Delta-Theta Ratio in VI)

3. Compare a 10-s averaged value of features with a pre-determined threshold.

4. Upon both features crossing thresholds, trigger stimulation via AO to shaker, and digital outputs

 

By connecting these digital outputs into a second DAQ board, we can read them into our sleep scoring software to confirm when stimulation occurred.

 

As previously states, the VI runs for an amount of time, but then ceases to write the waveform to the output.  I know this code is not ideally configured in any way, shape, or form.  But as I said, I'm still on the learning curve, and I did not write the code (with the exception of the threshold comparison, digital outputs, and EEG filter bank sub VI).

 

Hopefully that clears things up some.  

 

0 Kudos
Message 4 of 5
(3,417 Views)

Bob mentioned some general style guidelines, but here are some specific points that I think are causing your problems:

 

1.  The error handling.  In the top loop alone there are 5 parallel error wires.  The loop only exits based on two of them.  Even then... the exit condition is checking the error status of the DAQmx Write thread before the write is called.  There is no shift register on the error wire so any error produced by the DAQmx Write will be lost when the loop comes back around.  

 

2.  The task is set to auto start so I guess conceivably it could just keep starting itself back up and never report errors to you.  Set auto-start to FALSE (you are already starting the task on First Call, and should only be starting the task once if everything is working properly).

 

3.  The loop speed is being limited by two parallel tasks (the read and the write).  You are reading 1 second worth of data, so the read call (and thus the loop) will wait for 1 second before going to the next iteration.  You are also writing 1 second worth of data.  So... you are writing exactly enough data to make it to the next loop iteration.  There is no data in the buffer to start out, so if there is any delay in the write the output task will underflow (since regeneration is disallowed).

 

 

So with the combination of these three points, I could see a scenario where the output task is generating underflow errors but you are not seeing them due to the error handling (and the auto-start will succeed and will mask the error so when you close the program you might not even seen it then).  The fix for the first two points should be pretty straightforward.  For the third, instead of configuring a 3 second software buffer (which is actually never used beyond 1 second due to your loop timing), write 3 seconds worth of 0s to the task outside the loop before starting it.  This will configure the 3 second buffer and put some initial data in it so that you don't get an underflow and the full 3 second buffer is actually used.

 

 

 

Here are some other points that probably are not causing this specific problem but stood out to me nonetheless:

 

4.  The bottom loop does not exit when the top loop does.  You forgot to release your queue reference when you're done (the loop synchronization in some of the examples does it this way where releasing the queue reference will cause the dequeue function in the bottom loop to return in error which exits the loop).

 

5.  The phase inputs are never being updated for your waveform--your output will have discontinuities at frequencies that do not repeat an integer number of times in your buffer (which happens to be 1 second).  Better yet just let the function generator vi take care of phase for you (only the multiplication belongs in the case structure--you need just one instance of the function generator VI).

 

6.  The local variables create a race condition.  In a given loop iteration, you cannot determine if the logic is executed using old or new data (or some mix of old and new data).

 

7.  You are performing file I/O in your control loop.  File I/O is expensive and non-deterministic and probably belongs inside its own thread.

 

8.  You are using a USB device for a feedback system.  If you need tighter control you might consider a bus with lower latency (it sounds like you might be OK with USB though... just pointing it out).

 

 

 

Best Regards,

John Passiak
0 Kudos
Message 5 of 5
(3,394 Views)