Measurement Studio for VB6

cancel
Showing results for 
Search instead for 
Did you mean: 

Continuous Dynamic Analog Output (Waveform Generation)

I just wanted to share a few ideas and notes about an applicaiton that i have developed for continuous dynamic analog output, or waveform generation.   In National Instruments examples there is a program called Cont Gen Volt Wfm, which is a good example to start looking at for continous generation.  However, the problem is that it starts and stops by pushing a button.  What if you want to have a set of waveforms run, which can be all different types and then stop when they are done playing?   There is not a good example of that, and I wanted to provide a little bit of advice since i have created something to do that task. 
 
I first developed the application using the Traditional DAQ driver, but then migrated it to DAQmx recently and have enjoyed some of the greater flexibility of the different functionality.  Anyway, the requirements of my application were to take user input (time and voltage value ranges) on up to 4 channels and run the waveforms one right after the other.   The biggest difficulty was in working with the circular buffer and making sure that it was updated with new points before it finished outputing what it had already received.  If I didn't update it fast enough (using no regeneration) then it would throw an error saying that the buffer was not updated fast enough (it advised to increase the buffer size or decrease the frequency at which the data was output).   That doesn't sound that tough, but several of my first methods were not successful.  The first method I tried involved using a while loop to write a new half-buffer of data when the amount of write space in the transfer buffer was greater than or equal to the number of data points I wanted to write.   Well, that worked okay, but after i wrote the last half-buffer of data in my waveform and exited my while-loop i had to figure out how to determine when that last amount of data had been written.  I first tried using a second while-loop that would wait until TaskIsDone returned true, but I always received an error stating that an error had occurred and the generation had stopped to prevent the regeneration of old data. 
 
Next, i tried changing the conditions of the second while-loop to check the TotalWriteSamplesGenerated Property, which had improved success but didn't solve all of my problems.   In my application i had several other timers running that executed various features and would sometimes interfere when it was time to write to the transfer buffer.   To solve that problem I made the task of writing to the transfer-buffer a timer related function so that it would get executed whenever it was needed.   I still had a while-loop running but this time all it did was to check the value of TotalWriteSamplesGenerated  vs. the size (in data points) of the waveform i was outputing.   If the samples generated were greater than or equal to the size of the wave then i exited the while-loop and moved onto the next wave.  Well, once again i had to make a small adjustment to have a robust application.  When you set a while-loop to exit on a boundary condition you are living on the edge, and sometimes an error would occur.   To fix this issue i made sure that the while-loop would exit a small amount before the end of the wave.  When the data is being output at 2000 points per second then stopping a few data points early will not change the look of the waveform. 
 
Finally, that last hurdle i had to get over was that my application was using a large portion of the CPU (nearly 100%).   I am using an older DAQmx driver (7.5) and I plan to upgrade, but i was wondering if it could be other factors as well.  Anyway, i knew from my development in C/C++ that there was a sleep() function which would halt the thread of execution for a user specified amount of time.   So, i used the same function in my project and after every 1000 samples had been output I would make a call to the sleep() function to let the processor have some time back.   By making the call to the sleep function it has reduced the use of the processor by nearly 45%.   The tricky part here was that i had to figure out how often and for how long i would give control back to the processor.  This issue i am still not sure if I have cleared up entirely.   Is it the DAQmx driver?  Is it inefficient code?  The while-loop where i wait for the waveform to finish is a very basic loop and while it is running i have some other timers going, but nothing that should chew up 100% of the processor.   I am hoping that by upgrading my driver that could help the issue, but i am not sure.    
 
I hope this post proves useful to someone, and I hope this was the right place for the post. 
0 Kudos
Message 1 of 7
(9,380 Views)

Hi  GVanHorn!

I was reading your posting about the continuos waveform generation and your solution  looks great. I need to develop a similar application where I'm planning to stream in sequence several waveforms arrays to an analog output. Every waveform takes about 30 minutes to play and before the generation time of the previous waveform is over, the buffer has to be filled out with the data for the new waveform generation, so this application sounds very close to yours. I'm wondering if you could share some of the code you use to acomplish this task so I can get new ideas. I've trying to found a good example in NI 's website but I haven't found anything similar . I'm developing my application using LabWindows/CVI  8.1.

Many thanks is advanced!

Giovanni G.

giogonza@hotmail.com

0 Kudos
Message 2 of 7
(8,872 Views)

Hello Giovanni,

 

Just in case GVanHorn isn't available to reply (since his post is more than a year old).  I just wanted to say that you may want to look at the CVI example program called "ContGen-IntClk.prj" as this should be a good starting point.  You could easily modify this program to read data from a file each loop iteration and buffer the waveform that way.  You'll want to generate continuously and turn off regeneration so you know if you keep the buffer full enough.  I would recommend writing enough samples to the buffer each loop iteration so that you don't have to run the loop more than 10 times a second.  For instance if you want to generate samples at a rate of 100 kHz then make sure that with each DAQmx Write call you buffer at least 10,000 samples from your file.

 

I hope this helps get you started, and have a great night!

 

Cheers,

Brooks
0 Kudos
Message 3 of 7
(8,851 Views)

Hi Brooks!

Thanks for your replay. As a matter of fact I've seen the example you mentioned but I'm a little bit confused on how to programmatically update the content of the buffer without affecting the current generation. Remember, since I'm planning to play a huge file I have to refresh the output buffer every once in a while, but at the same time a need to be sure that I'm not going to overwrite its content because that will interfere my current generation. I really don't know how to accomplish this. Any help would be appreciated. Thanks!

 

0 Kudos
Message 4 of 7
(8,827 Views)

Hello Giovanni,

The analog output uses a first in first out (FIFO) buffer.  When you use another DAQmx Write VI to write more samples to the buffer they are added to the end rather than overwriting the samples that are currently in the buffer.  The thing you need to look out for is running out of samples in the buffer before you add more.  You can call a DAQmx Write whenever you like without interfering with the current generation because the buffer will output all of the previous samples before it begins using the ones you wrote most recently.  I would recommend reading a chunk or points from your file each loop iteration and sending them to the DAQmx Write.  A good target to aim for would be running the loop 10 times a second.  With that in mind you should read and write enough samples to sustain 0.1 seconds of generation at the rate you've selected.

Cheers,



Message Edited by Brooks_C on 05-20-2008 08:30 AM
Brooks
0 Kudos
Message 5 of 7
(8,813 Views)

Hi, I'm posting this message again because my situation has changed a little bit. Now I need to play a sequence of different waveforms. All the waveforms have different parameters like size, sampling rate, amplitude, etc. I have a script file (text file) that holds the parameters necessary for the AO generation. This is the logic:

 

Read sequence waveforms from text file

            Loop

            Read data waveform from data file

Read AO conditions: start time, end time, sample rate, channel

Call Generate AO

                        Configure the task: timing, number of samples, etc accordingly

                        Start task         

                        Is this task done?

            Is this the last AO generation?

            yes: End AO generation

                        no : go to the top of the loop

 

I’m kind of lost about how to accomplish this since every AO generation is different. I'm having problems while trying to recall the next AO generation. I do not know how to synchronize these two events. Do you have any sample code or suggestions?

(I'm using Labwindows CVI 8.2 and DAQmx driver)

Thanks a lot.

0 Kudos
Message 6 of 7
(8,625 Views)

Hello giogonza,

 

In order to change task parameters such as the rate you need to stop the task.  In your current structure you will have to stop the task, configure the next task, and then restart the task.  If you take this approach then it will be difficult to synchronize the tasks because there will be some software timing in between waveforms, but you could probably get this within a few ms.

 

If you require better timing then this then you'll need to configure your waveforms to be output with the same channel parameters.  For instance, if you have 2 waveforms that need to be output, one at 1 kHz and the other at 2 kHz, you could change your first waveform to have duplicate points (or interpolate points) so that it had twice as many and then could be output at 2 kHz.  Then you could turn off regeneration for your output channel and just buffer both waveforms without changing any of the channel parameters.  The second method would be the cleanest solution, but you'll need to modify your waveform data to have a consistent update rate.

 

Cheers,

Brooks
0 Kudos
Message 7 of 7
(8,611 Views)