12-14-2021 12:51 PM - edited 12-14-2021 12:52 PM
I'm developing an application that continuously measures voltage on an arbitrary number of DAQmx channels. I want to low-pass filter the readings before logging & displaying the data.
Since the number of channels can change at runtime, I plan to process the waveform data in a loop. That means I can't use the (stateful) Butterworth Filter PtByPt.vi. But even the regular Butterworth Filter.vi is stateful. It has an init/cont flag, and stores state in a shift register. The init/cont flag gets passed all the way down into lvanlys.dll (IIR_Filter2), suggesting that even the underlying C library is stateful!
There's a feature request from 2012 describing this problem: Stateless Mathematics and Signal Processing VIs
Am I misinterpreting the VIs? Does anyone have have experience working around this limitation? I'd really prefer using an known library rather than re-implementing filters with math primitives.
Solved! Go to Solution.
12-14-2021 05:26 PM
The signal processing palette includes filtering functions that accept an array of waveforms. Internally, they hold separate state information for each waveform in the array so you don't get the kind of "contamination" that concerns you. You can dive down into them to see how it's done -- using various off-palette helper functions. Basically, the filter's internal state is stored in in a kind of higher-level "wrapper" function which calls the core stateless low-level function that performs the filter math.
There are actually quite a few different available approaches to filtering within the palettes. Also be sure to right-click the functions and look for even more "polymorphic" options if there's an option to "Select Type" in the context menu.
If you get your data from a DAQ device, use the version of DAQmx Read that puts the data into a 1D array of waveforms (each containing a 1D array of sample data) instead of directly reading a 2D array of sample data that carries no timing information along with it.
-Kevin P
12-14-2021 06:40 PM
@OneOfTheDans wrote:
I'm developing an application that continuously measures voltage on an arbitrary number of DAQmx channels. I want to low-pass filter the readings before logging & displaying the data.
Since the number of channels can change at runtime, I plan to process the waveform data in a loop. That means I can't use the (stateful) Butterworth Filter PtByPt.vi. But even the regular Butterworth Filter.vi is stateful. It has an init/cont flag, and stores state in a shift register. The init/cont flag gets passed all the way down into lvanlys.dll (IIR_Filter2), suggesting that even the underlying C library is stateful!
There's a feature request from 2012 describing this problem: Stateless Mathematics and Signal Processing VIs
Am I misinterpreting the VIs? Does anyone have have experience working around this limitation? I'd really prefer using an known library rather than re-implementing filters with math primitives.
I had this problem before. The solution is to use a unique filter for each channel. (Can't post the VI due to company limitations, but can post screenshots)
The first thing I do is open a bunch of filter primitives dynamically and create a "Reference" for each filter, see below
Create a reference for the filter primitive
Then I use that filter reference for each channel with a dynamic call, see below. Note In the screenshot below, I have some feedback nodes. Those nodes are there in case the user changes the filter somehow and I want to reset it. By using the same filter reference for each channel the "history/state" is preserved correctly.
Call the filter dynamically. You can even do it in parallel!
Lastly, when your program is finished be sure to close the filter references. See below.
Close the references to avoid a memory leak.
12-14-2021 08:16 PM
@OneOfTheDans wrote:
I'm developing an application that continuously measures voltage on an arbitrary number of DAQmx channels.
Can you a bit more specific on the "arbitrary" number? Is there a relatively small upper limit or can it be gigantic? If the number is not too large, you could use a parallel FOR loop with sufficient parallel instances
12-14-2021 08:27 PM
@altenbach wrote:
@OneOfTheDans wrote:
I'm developing an application that continuously measures voltage on an arbitrary number of DAQmx channels.
Can you a bit more specific on the "arbitrary" number? Is there a relatively small upper limit or can it be gigantic? If the number is not too large, you could use a parallel FOR loop with sufficient parallel instances
This becomes problematic if running continuously because of the state information for the filter. The filter is either resetting or you may use the previous state from a different channel. This important for the OP because he wants to save the filtered data.
By creating specific instances of the filter that you can reference, you can keep state information, even when running in parallel.
12-15-2021 05:35 AM
Unless you really *need* For Loop parallelism, it'll be easier to use the available waveform filter functions. Like this:
Note: I'm assuming a pretty normal DAQ application where the user may specify a fairly arbitrary # channels to collect, but once they start running, that # stays constant throughout that particular run. DAQmx won't allow the # channels in a task to vary during a given run anyway.
Further note: I've illustrated the case where all channels are filtered according to the same filter specs (though each will retain its own unique state information). There's a different polymorphic instance that allows you to define unique filter specs for each channel.
-Kevin P
12-15-2021 08:26 AM
Thanks for the great responses everyone!
@altenbach wrote:
Can you a bit more specific on the "arbitrary" number? Is there a relatively small upper limit or can it be gigantic? If the number is not too large, you could use a parallel FOR loop with sufficient parallel instances
Yes, I could reasonably bound it as 2-64. As mentioned, I think the parallel for loop wouldn't work, but I could build a giant subVI that indexes my array to 64 manually-dropped instances. It's a good work around, but I'd rather avoid building & maintaining that.
@mcduff wrote:![]()
I love this solution, thanks for sharing! It also means you can use a different type of filter for some of the channels, if needed.
@Kevin_Price wrote:
This is exactly what I was looking for, thank you! I'm already taking a 1D WFM from DAQmx. I missed this VI in the palette, and went down looking at the specific Butterworth filters, and their core VIs, which don't support N chans. But this is perfect for my application.
Thanks again!