LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Moving average in FPGA using block ram for 8x1024 (many) elements

Hello Community,

 

I am currently working on an implementation of a running average on a cRIO9066 and NI9201 ADC module. The ADC values need to be averaged (approx. up to 1024 values for each of the 8 channels, 256 might be enough in the end) and this needs to be implemented on the FPGA. 

 

The plan is to implement this using block memory, however I do not fully understand where the mistake in my code is. My idea is to shift all the values in the memory by one, and then insert the new value at memory index 0. After that I loop over all memory values to add them, and then divide that value to get an average. Please find the VI attached and below.

 

Currently it looks like the output value is not averaged at all, but just the input value (shifted), meaning maybe all values in the block memory are the same?

 

I also do not understand why I need to implement a feedback(forward) node to read from the block memory.

 

Any pointers are greatly appreciated.

 

Implementations with arrays or delays fail, because they need to much space.

 

Best regards,

Gregor

ghe8_0-1657539757548.png

 

0 Kudos
Message 1 of 8
(1,902 Views)

Your shift loop is bugged, drop the +1.You can skip the shift entirely if you just write to i % 1024 each iteration (actually reset to zero if  i>= 1024 after increment to avoid overflow).

 

Also be mindful of your accumulation variable for the average, it might overflow.

Message 2 of 8
(1,848 Views)

You can actually avoid the shift loop altogether.

To do a rolling average it does not matter what order the elements are in memory. Instead just keep track of the oldest element and replace that.

If you also track the sum then you can just subtract the removed value and add the new value and reduce this to just a few cycles of work.

You can imagine it as sum is:

sum = previous sum - oldest value + new value

James Mc
========
CLA and cRIO Fanatic
My writings on LabVIEW Development are at devs.wiresmithtech.com
Message 3 of 8
(1,841 Views)

I recommend making a test bench and running this in simulation mode with known data.


Certified LabVIEW Architect, Certified Professional Instructor
ALE Consultants

Introduction to LabVIEW FPGA for RF, Radar, and Electronic Warfare Applications
0 Kudos
Message 4 of 8
(1,817 Views)

Thanks a lot for your pointers, find below my adapted solution with the your comments implemented. Works so far as expected, and unsurprisingly significantly faster.

 

I couldn't get the FXP math working correctly so I converted to SGL for now.

 

I'll now test if I have enough space on the FPGA adding to my main VI.

 

If you see any other obvious optimizations, please do let me know.

 

Best,

Gregor

 

 

ghe8_0-1657635457527.png

 

0 Kudos
Message 5 of 8
(1,814 Views)

After some further tests, there seems to be an issue unfortunately. When I hook up a power supply to the ADC with 0.5V, and load the VI (I made a small plotting VI just for test purposes, see attached) everything seems fine, and the averaged value is in the middle of the raw values.

 

Now if I turn the power supply to e.g. 8.8V, the average value starts to drift away very slowly (over the range of say 10min). So I am thinking this might have something to do with the initialization? Is one of my nodes initialized wrong? But even if so, why would it drift at such a slow rate?

 

Best,

Gregor

 

White: raw values, Red drifted average after ~10min

 

ghe8_0-1657710716691.png

 

Addition: The feedback node in the 'Counter with reset' needs to be initialized with -1 not 0 as in my previous post

0 Kudos
Message 6 of 8
(1,795 Views)

This is likely due to the accumulation of errors resulting from the conversion to floating point. An easy remedy would be to use doubles instead of singles. Better would be to get the fixed point math working although I haven't done any of that myself. You would need to cast your incoming data to a fixed point type with higher range and go on with your calculations.

 

The initial counter value does not matter, you can start anywhere in the ring buffer.

 

The second counter check should also check for 1024, or the increment needs to move after the comparison.

Message 7 of 8
(1,760 Views)

Yep, found these exact two mistakes you are pointing out, and just got it to work in FXP (doubles don't work on the FPGA). Thanks all for your help!

 

For anyone interested, the for now final VI is attached.

 

Best,

Gregor

 

ghe8_0-1657724042718.png

 

 

 

Message 8 of 8
(1,758 Views)