LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Implement medium frequency sampling correctly

Solved!
Go to solution
I'm writing a data acquisition program that reads voltage and current data from a 3 phase generator, ie. there are 3 channels of voltage data and 3 channels of current data (also represented as voltages) coming into my USB 6009. 

 

The waveform shape is not yet known but likely to be pretty much sinusoidal up to about an electrical frequency of say 1.5kHz. I need to work out the frequency (reliably) in realtime so that I know the speed of the generator. I've been using the 'Harmonic distortion analyzer' VI to do this- deep down it basically does an FFT on the data. I suspect that this is too much of a processing overhead though because if I increase the sampling rate to more than about 1000Hz I start to have problems - and if the data is max 1.5KHz I need to sample and analyse at at least 3KHz of course.

 

So-- the question is, how can I sample at say 3-5KHz and work out the fundamental frequency of one of the channels in realtime without causing everything to fall over?

Any answers greatly appreciated.

 

Dave

 

0 Kudos
Message 1 of 14
(4,148 Views)

Dave,

 

If the zero crossings of at least one channel are clean, you could detect those and simply count the number of samples between them to get the period. Some simple comparisons and logic should take less computing resources than FFTs.

 

The frequency likely changes slowly so you may be able to optimize the search by only looking at a few samples near where the expected zero crossing is located. Whether the overhead to track the expected location is greater than continuous checking needs to be considered.

 

Lynn 

0 Kudos
Message 2 of 14
(4,146 Views)

yes, that's what I thought. However if there is anyway to avoid doing this 'the hard way' then I would love to hear about it - since I'm a bit short on time.

as per many things in labview, i would have thought this is quite a common need (to find the frequency of a sinusoidal input, with low processing overhead)-- so perhaps someone has already written a VI to do it...

 

dave

0 Kudos
Message 3 of 14
(4,138 Views)

Dave,

 

Please post your VI with some typical data saved as default.  Someone may be able to suggest faster ways of doing other parts so that the FFT can be fast enough.

 

How many samples do you feed to the FFT at a time?  Speed and resolution tradeoffs may help.

 

Lynn

0 Kudos
Message 4 of 14
(4,135 Views)

sure, vi attached. I don't have the USB6009 with me at present so will need to post data tomorrow. But if you spot anything obviously stupid of me, let me know!

I'm considering trying with a high speed circular buffer for the input loop instead.

Dave

0 Kudos
Message 5 of 14
(4,126 Views)

Dave,

 

A few things you can do to speed things up: Move indicators and analysis outside the acquisition loop.  Queues or Action Engines are good ways to do this. You can send the updated sample count back the same way.  Look at the Producer/Consumer design pattern  which ships with LV for an example of how to use parallel loops this way.    Convert the sample count to an integer rather than a double.  Avoid the coercion dot at the input to the Analog Read VI.   

 

The basic Averaged DC RMS VI is used twice.  Do you have a substantial offset which must be removed?  On all channels?  If so, you may want to use the signal with the offset removed for the frequency determination.

 

You divide by one for input scaling.  Perhaps this will change later, but omitting it or scaling after the time-critical parts are done may be better.  Also multiplication is slightly faster than division. 

 

Use shift registers rather than local variables in the lower loop.

 

Lynn 

0 Kudos
Message 6 of 14
(4,124 Views)

Thanks for all your help and prompt replies. Lots to digest there!

 

1) Move indicators and analysis outside the acquisition loop: makes sense - apart from the FFT? or that too? suppose makes sense because the acquisation loop will basically spit out a large block of data every 0.5 seconds or so

2) Not quite sure what queues / action engines are - need to read up on that with producer/consumer example as you suggest

3) How do I get rid of the coercion dot at the analog VI input?

4) I do need to remove a fairly large offset - will it make any difference whether I do freq determination with or without offset removed?

5) Input scaling is not divide by 1 - I just haven't set it properly yet. It's divide by 3, and 15. So you think I should multiply by 0.3333 and 0.066667 instead?

6) Shift registers rather than local variables in the lower loop - don't quite understand what you mean here. I'm using the local variables to get the data from the top loop to the bottom loop - as suggested by various people at NI and also various books I've read! How would I do this with shift registers instead?

 

Thanks again

Dave

 

0 Kudos
Message 7 of 14
(4,122 Views)
Solution
Accepted by topic author oilyfingers

Dave,

 

1)  I prefer to put all analysis (like FFT) in a separate loop.  The acquisition loop  only does acquisition.  It acquires data and puts it into a queue or action engine to be used elsewhere.  This way the acquisition timing is not dependent on the time required to do the analysis or display or save to file...

2)  Queues are built in functions which allow data to be passed to independent parts of the program efficiently and without the risk of race conditions inherent with local or global variables.  They also have nice features like error clusters and timeouts.  Action Engines are VIs in the form of a while loop with an uninitialized shift register to retain data.  They usually contain a case structure to allow selection of various actions, such as Initialize, Write, and Read, or more complex things like return subset or average accumulated data.  Search the Forum for Ben's Nugget and many other posts on the subject.

3)  Convert the  data type to an integer.  You obviously cannot acquire a fraction of a sample, so using a data representation which supports fractions is unnecessary.  In this case it is not a big deal, but coercion dots can tell you that LV is doing extra work behind the scenes to change data types, perhaps not the way you wanted them changed.

4)  Yes and no.  The FFT should work although the signal to noise ratio is reduced.  Think of the DC component as being the "noise" in that calculation.  If you want to do zero crossings then it is essential that the offset be removed.  With the offset present the zero crossings will be shifted away from the mid points of the sinusoidal waveform or the signal may not cross zero at all if the oofset is greater than the peak value of the periodic component.

5)  I suspected something like that.  Multiplying is somewhat faster than dividing so it is preferred if speed is important.  If it is more convenient for the user or the  programmer to enter the divisors, let the program calculate the reciprocal multipliers.  Just do it once, outside the loop where it will not affect the timing.

6)  I missed that you were moving data between loops.  Can't do that with the shift register.  See item 2) about queues or Action Engines.  Notifier could be used for the Stop also.  My opinion: The only place you need a local variable is if you need to write a value to a control, such as when setting a saved configuration from a file.

 

Lot's to learn.

 

Another question: In the original post you said you needed the frequency determination in "real time."  That is a slippery term.  Are you using it for something other than setting the number of samples to read?  How fast can the frequency change?  What are the consequences of a delay in getting the frequency?  How much delay can you tolerate before the consequences are unacceptable?

 

Lynn 

0 Kudos
Message 8 of 14
(4,097 Views)

Dear Lynn,

 

Once again - thanks. I feel like I'm now getting there.

I've rewritten the code so that the fast stuff happens on its own in a small loop. See attached.

What do you think?

 

Later I will look at queues etc - for now I'll stick with local variables just to get something working.

 

I've managed to get the 'scope' timebase approximately triggered, although it's not bang on, depending on the frequency I input, it drifts slightly - I'm not sure what's wrong. It may be a signal processing issue because the harmonic analyzer is not working on the data continuously, it is working on chunks. Hmmmm...

 

I don't need the frequency in 'real time' - it's not for a control loop or anything, just to record data. A small delay (as there will be) is acceptable. Apart from complications with triggering the chart as dicsussed above.

 

Dave

0 Kudos
Message 9 of 14
(4,091 Views)

Dave,

 

That is the general idea.

 

I am not sure what you are trying to do with your scope displays.  Are you trying to display an integer number of cycles of your waveforms?  You may be getting drift because you are not doing anything that I can see which would "trigger" the scope display at a rising zero crossing.  The sampling is continuous and the reading occurs whenever the specified number of samples is available.

 

If you want a display like a triggered scope, use the Threshold 1D Array function to find a location in one of the data arrays where your triggering criterion is met. (Note this function only works for increasing signals.  If you want falling triggering, you need to do some extra work).  Then using your frequency information and the trigger threshold point, grab an array subset for display.

 

Your data acquisition loop will iterate about every 1100 ms with the values currently entered.  Your "low speed" loop will iterate as fast as every 100 ms if all the analysis is done in less than that amount of time. This means that your scope will analyze and plot the same data up to 11 times before new data becomes available.  This is one place where the queue or Action Engine can be helpful because they can be configured to indicate when new data is available or to wait for it.

 

Lynn 

0 Kudos
Message 10 of 14
(4,088 Views)