LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Continuous filtering

Solved!
Go to solution

I have created modified multi-filter based on VI shared by johnsold in this post. Thanks @johnsold for those VIs.

 

I am calling MultiFilter.vi every 100ms after DaqMx Read and passing 8channel 100 samples data in 2D DBL array format to MultiFilter.vi.

 

filter.pngMultiFilter.viMultiFilter.vi

Though I am able to get filter working, but there's break observed in a waveform. Something like filter restarts. So my query is, how to achieve continuous filtering? Filter.viFilter.vi

Download All
0 Kudos
Message 1 of 14
(5,413 Views)

Not sure what the shift register in MultiFilter.vi is supposed to do, but it's doing anything at the moment. Seems to me you need to use the output of the selector.

 

OT: Is this just an exercise\test? The way the call and collect is being used doesn't seem useful at all. Each loop still waits until the VI is completed, and it's a very complicated way to do it compared to a Call by Reference.

Message 2 of 14
(5,376 Views)

Which of the two plots is the input and output? 🙂

Cannot open your code as I have only LV2015. 

 

The problem that you see might be due to initializing the filter.vi every time the loop runs. 

Or it might just be the discontinuity in the input data that you repeat. 

You also do not seem to wire the sampling frequency to the Filter.vi. 

Hope the default value of the control is the actual sampling frequency of your data. 

 

Have you set the Filter.vi to re-entrant and pre-allocated clones as mentioned in the last post of the thread. 

 

There can also be some issues with your initialization code.

Also, in the multi filter.vi, the initialization case structure's selector is wired to a control outside the while loop.

It seems you initialize when Init control is False? 

What happens in the second iteration of the loop, will it still run the False case?

 

Also, you use uninitialized shift register for the init.

You assume that it will have false in the first iteration.

To guarantee it you will have initialize the shift register with false. 

 

Simplest would be to use the loop iteration terminal, i,  for initialization. 

That is, init if i is equal to zero. 

BR
Message 3 of 14
(5,366 Views)

wiebe@CARYA wrote:

Not sure what the shift register in MultiFilter.vi is supposed to do, but it's doing anything at the moment. Seems to me you need to use the output of the selector.

 

OT: Is this just an exercise\test? The way the call and collect is being used doesn't seem useful at all. Each loop still waits until the VI is completed, and it's a very complicated way to do it compared to a Call by Reference.


Thanks for a quick response. Yes, I have made mistake in Initialization code - i have not wired Init input & USR properly. Very silly mistake indeed. Let me rectify the code and test whole thing again.

 

No, it's actual project. No specific reason to use call & collect, i just copied the code from link provided at start of my post. I guess, by using call & collect, multiple calls to Filter.vi are started simultaneously. Let me study call by reference and how it can be used in this case.

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

@Kallis wrote:

Which of the two plots is the input and output? 🙂

Cannot open your code as I have only LV2015. 

 

The problem that you see might be due to initializing the filter.vi every time the loop runs. 

Or it might just be the discontinuity in the input data that you repeat. 

You also do not seem to wire the sampling frequency to the Filter.vi. 

Hope the default value of the control is the actual sampling frequency of your data. 

 

Have you set the Filter.vi to re-entrant and pre-allocated clones as mentioned in the last post of the thread. 

 

There can also be some issues with your initialization code.

Also, in the multi filter.vi, the initialization case structure's selector is wired to a control outside the while loop.

It seems you initialize when Init control is False? 

What happens in the second iteration of the loop, will it still run the False case?

 

Also, you use uninitialized shift register for the init.

You assume that it will have false in the first iteration.

To guarantee it you will have initialize the shift register with false. 

 

Simplest would be to use the loop iteration terminal, i,  for initialization. 

That is, init if i is equal to zero. 


Amazed to see such elaborate analysis so quickly!

And yes, I have made silly mistake with Initialization code. Let me rectify and recheck.I will use i=0 method for init.

0 Kudos
Message 5 of 14
(5,347 Views)

 

I think there's a few basic changes that will make a big difference:

 

1. Make sure your filtering function is configured to make pre-allocated reentrant clones.  You can set this under VI properties->Execution properties with the vi open in the editor.

2. When you open a VI server ref to the function, use the 0x08 value to specify that you're opening an *instance* of a clone.  Then the refnum uniquely identifies that *instance*.

3. Use the regular old Call By Reference function.  It's easier for simple, inline, execute-and-return-fast functions.   It still allows you to wire your inputs and outputs for convenience.  

4. This is the big one.  Instead of opening 1 reference to the filter function, open as many unique references as the # of channels in your data set.  Then the row # from your 2D array will always correspond to the same filter function instance and you won't see the discontinuities.

    Filter functions save state information internally to "remember" the recent past data they've been presented.  The way you've got it programmed now, each iteration of the loop places an abrupt transition in data seen by the single filter function as you go from the last sample from one row to the first sample in the next row.

 

Have a look at this post for an illustration of what I'm talking about.  Note that you do *not* need the 0x40 flag.  (For a fairly extensive but occasionally meandering thread discussing that, check out this other thread.)

 

 

-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 6 of 14
(5,337 Views)

@nik2013 wrote:

wiebe@CARYA wrote:

Not sure what the shift register in MultiFilter.vi is supposed to do, but it's doing anything at the moment. Seems to me you need to use the output of the selector.

 

OT: Is this just an exercise\test? The way the call and collect is being used doesn't seem useful at all. Each loop still waits until the VI is completed, and it's a very complicated way to do it compared to a Call by Reference.


Thanks for a quick response. Yes, I have made mistake in Initialization code - i have not wired Init input & USR properly. Very silly mistake indeed. Let me rectify the code and test whole thing again.

 

No, it's actual project. No specific reason to use call & collect, i just copied the code from link provided at start of my post. I guess, by using call & collect, multiple calls to Filter.vi are started simultaneously. Let me study call by reference and how it can be used in this case.


The call and collect will start multiple instances simultaneously. But in this can, a for loop configured with parallel execution will do almost the same (the error in shift register won't work). It is much easier to grasp.

 

OT1: I personally never used call and collect or call and forget, because every time I try it, LabVIEW crashes or blocks my VI for editing even though nothing is running.

 

OT2: If you do use call by reference, the entire VI server construction is basically a home made OO framework (the VI reference choses between to childs of a "parent"). A parent class with a (dummy) child and filter child would really clear this code up.

0 Kudos
Message 7 of 14
(5,314 Views)
Solution
Accepted by nik2013

Kevin_Price's observation #4 was spot-on. 

Also, one thing that I overlooked was that the init/cont terminal in the Butterworth Filter.vi initializes with False (that is easy to miss). 

Modifying johnsold's original VI as below gives no discontinuities in the signal. 

 

 MultiFilter.png

FrontPanel.png

BR
Message 8 of 14
(5,290 Views)

Now that it works, can you try what happens if you use Call By Reference in a for loop set up for parallel execution? It would simplify the code dramatically.

 

I'd do it myself if the VI was attached. The snippets still don't work.

0 Kudos
Message 9 of 14
(5,267 Views)

Thanks @Kallis for solution with image. Your suggestion to create array of Vi Ref worked perfectly. 

 

Thanks @Kevin_Price and @wiebe@CARYA for your tips & link to an example, it was very useful to implement MultiFilter with 'Call by ref'. I replaced original Call & collect with Call by ref. And was surprised to see simplicity it brings! VI and images are attached herewith.Image-1-Main VI (DaqMX Read)Image-1-Main VI (DaqMX Read)

 

Image-2-MultiFilterImage-2-MultiFilter

 

Image-3-Filter(re-entrant pre-allocated clone)Image-3-Filter(re-entrant pre-allocated clone)

 

Image-4-Filtered output(upper chart)Image-4-Filtered output(upper chart)

 I hope, it's alright to ask few more queries, after accepting an answer.

1. This solution works only if fixed number of are passed to MultiFilter.Vi. If I replace 100 with -1 @ DaqMx (Image-1) Read sample count (i.e. read all available samples), it passes variable lengths array (i.e. Rows 8, columns: varies 99/100/101/etc) to MultiFilter (Image-2). In this case, Main For loop of MultiFilter.vi  is not working at all (it doesn't go inside for loop). What could be the reason for that?

2. What could be the use of USR in Filter.vi (Image-3)?

 

Again, Thanks everyone for prompt & detailed responses.

Download All
0 Kudos
Message 10 of 14
(5,249 Views)