Multifunction DAQ

cancel
Showing results for 
Search instead for 
Did you mean: 

How many cycles of analog output to generate

Solved!
Go to solution

Hi, it might be a little stupid question but when I generace AO waveform in continuous mode I can decide how many cycles I want to WRITE to the Task(buffer) before I start the generation. My dilema is how many cycles to send in case of periodic functions. Isn't one period=one cycle enough. Would the output signal be somehow better if I use more cycles? 

Thanks

-Petr

LV 2011, Win7
0 Kudos
Message 1 of 7
(4,135 Views)
Solution
Accepted by topic author ceties

In certain special (and probably rare) cases, it may be better to define multiple periods in the buffer.  I once had a need to do that to make sure that the potential glitch from the final value in the buffer back to the first value was minimized.  The AO went to a servo that moved a human test subject, so motion needed to be as smooth as possible.

 

The problem can arise when a period of your AO waveform doesn't exactly fit an integer # of samples at your desired sample rate.  As a result, the voltage you'd *want* to generate after the last one in the buffer wouldn't quite equal the first value in the buffer.  I'll

illustrate with an extreme example.  Suppose you want to generate a waveform with a 3 Hz freq.  Suppose your sample rate must be 100 Hz (to be synced to other stuff in your system).  That means one waveform period equals 33.33333333... sample intervals.

If you put 33 samples in your AO buffer, the voltage step from the 33rd sample back around to the 0th sample won't be the right size for your waveform shape.  The waveform *wanted* to go to a value 2/3 of the way between samples 0 and 1.

 

A good solution here would be to define a buffer containing 3 waveform periods.  That equals 100.000 sample intervals and now

your generated waveform will not have a little anomaly every cycle.  In the more general case, you'd have to solve a little problem to make sure that some integer # of waveform cycles can correspond to a different integer # of sample intervals.

 

I posted a couple examples of methods to do this a few years ago.  Here's a link to the final post, but you should read the whole thread for more context.

 

-Kevin P

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
Message 2 of 7
(4,129 Views)

Thanks Kevin, I was sure that the hitch will be a fractional number of samples at some point. Nevertheless I actually have an inverse task - I let the user define the type of the periodic function, its freq and number of samples per period (sort of definition of quality) -> this as a result gives me the desired rate of the samples. I am aware that the oscilator cannot produce whatever noninteger frequency I give it but I believe that it is acurate enough so I don't have to worry about it.

LV 2011, Win7
0 Kudos
Message 3 of 7
(4,104 Views)

Hmm, at the end I addopted your way of generating the waveform since I thought this way I could have waveform of different frequencies on different channels...but I guess this is not really possible...Is it? More here

LV 2011, Win7
0 Kudos
Message 4 of 7
(4,035 Views)

Possible, yes, but maybe a little tricky.  (I followed your link but am replying here due to this thread's links to those buffer sizing examples that are going to be relevant to the discussion.)  Here are a variety of thoughts:

 

1. Your 2 ao channels will have to use the same sample clock -- let's say 100 kHz as you said in your example.

 

2. For your 6 kHz output, I'd start by supposing a minimum 50-sample regeneration buffer that will hold exactly 3.0000 cycles of the waveform.

 

3. Your 3 kHz output will also need to have 50 samples because the two ao channels need the same rate & number of samples.  However, for 3 kHz, 50 samples is only 1.500 cycles.

 

4. Now you'll need to find a good integer multiplier.  This example is easy -- make a 100 sample buffer that contains 6.000 cycles of the 6 kHz channel and 3.000 cycles of the 3 kHz channel.

 

5. Let's try a less friendly example now and use the buffer size calculator utility I linked to earlier.  Sticking with a 100 kHz sample clock, let's aim for 3.7972618 kHz and 5.4203196 kHz waveforms.  I'll calculate options for one and use that as a constraint on the other, maybe going back and forth a few times.

 

6.  I'll try ~3.7972618 first.  That gives me f_o/f_w = 100 / 3.7972618 = 26.334765751469 to use as my "Orig floating point value".  I run the utility and focus on the results for "N[]" (# of samples in the buffer) and "errors" (to judge accuracy of fit).  The 1st approximation gives N=53 and error=0.165 while the 2nd approximation gives N=79 and error=-0.00143.  Further approximations give much larger N values and much smaller errors.  Unless we get lucky with one of those larger N values, I'll be focusing on the 2nd approximation with N=79.

 

7. Now let's try f_o/f_w = 100 / 5.4203196 = 18.449096617845 as the "Orig floating point value".  The first approx has N=37 and error=0.0509.  Not too bad already, and there are progressively better options as you go down the list of iterations.

 

8.  Now what?  Well, we've gotta do a little mash-up to find an acceptable compromise.  I went looking for a reasonable-sized least-common multiple from among the possible pairings of buffer sizes.

   Here's exactly how I did it:  I ran one case, then copied the N[] results into a new vi, named it N1[], and converted it from indicator to control.  I did the same thing for the other case using the name N2[].  Then I looped over both while calculating the "least common multiple" of every eligible pair.  I then applied some engineering judgment to pick a preferred result.

   Criteria were lcm < ~100000 samples for buffer size, with small errors for either waveform.   I wound up with choices

of N1=79, N2=369, lcm = 79*369 = 29151 (because they are mutually prime), and both errors are in the neighborhood of only 0.001 compared to a perfect fit.

 

9. So the buffer size will be 29151 samples which will be generated at 100 kHz.  In those 29159 samples, you'll have 1107 full cycles of your 3.7972618 kHz waveform and 1580 full cycles of your 5.4203196 kHz waveform.  The fit error will be very small for both, limiting the tiny little glitch when the buffer wraps around on each regeneration cycle.

 

10.  I "cooked" an example I could post as a snippet.  It calls the utility function I linked to earlier which currently only returns the best result.  I picked a magic # for allowable error that would produce the result I illustrated.

 

-Kevin P

 

 

bufsize.png

 

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 5 of 7
(3,993 Views)

Hi Kevin and thanks for your example!!! This aproach makes sense but as I see it it will definitelly work for two channels with different frequencies of the desired signal. It will probably still be ok for three channels but since I try to make universal solution for anything up to 16 channels I guess I cannot use it. I would have to generate pretty huge 2D arrays (LCM over all the channel buffer sizes) that would have significant performance hit. Most likely for five channels it would not even fit into memory.

 

With that said I am very glad for your example since I learned something new.

LV 2011, Win7
0 Kudos
Message 6 of 7
(3,971 Views)

I've mostly done AO through E-series and M-series multifunction cards, so I tend to think of AO as being either 1 channel or 2.   Agreed, the approach I described isn't real easy to automate for the general case of even 2 channels and the problem compounds rapidly with channel count.

 

With more than 1 or 2 channels, you'll be better off doing non-regeneration with a big enough buffer that you can pretty confidently "hope for the best" with Windows.  When I've done non-regenerating output tasks, I like to aim to write about 1/3 buffer at a time after the initial fill.  Nothing magic about that #, it just seemed like a decent compromise where I didn't have to write real frequently but could still afford a good-sized Windows hiccup or two without a buffer underflow error.

 

-Kevin P

 

 

CAUTION! New LabVIEW adopters -- it's too late for me, but you *can* save yourself. The new subscription policy for LabVIEW puts NI's hand in your wallet for the rest of your working life. Are you sure you're *that* dedicated to LabVIEW? (Summary of my reasons in this post, part of a voluminous thread of mostly complaints starting here).
0 Kudos
Message 7 of 7
(3,961 Views)