Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
17049 Discussions

How to make a averager in VHDL

Altera_Forum
Honored Contributor II
5,075 Views

I have just readed a piece of VHDL code. It is used to average the signal value from AD(14 bit).  

The code i write below here: 

 

 

process(CLK80) begin 

if(CLK80'event and CLK80='1') then 

if(samplingTriggerReg='1') then -- synchronization with the sampling trigger 

avCStateReg <= "00000";  

else 

case avCStateReg is  

when "00000"=> if(sigCLatchReg='1') then avCStateReg<="00001"; end if; 

when "00001"=> if(sigCLatchReg='1') then avCStateReg<="00011"; end if; 

when "00011"=> if(sigCLatchReg='1') then avCStateReg<="00111"; end if; 

when "00111"=> if(sigCLatchReg='1') then avCStateReg<="01111"; end if; 

when "01111"=> if(sigCLatchReg='1') then avCStateReg<="11111"; end if; 

when "11111"=> if(sigCLatchReg='1') then avCStateReg<="11110"; end if; 

when "11110"=> if(sigCLatchReg='1') then avCStateReg<="11100"; end if; 

when "11100"=> if(sigCLatchReg='1') then avCStateReg<="11000"; end if; 

when "11000"=> if(sigCLatchReg='1') then avCStateReg<="10000"; end if; 

when "10000"=> if(sigCLatchReg='1') then avCStateReg<="00000"; end if; 

when others => avCStateReg<="00000";  

end case; 

end if; 

end if; 

end process; 

 

dfTrigCReg <= '1' when avCStateReg="10000" else '0'; 

 

 

 

process(CLK80) begin 

if(CLK80'event and CLK80='1') then 

if(samplingTriggerReg='1') then -- synchronization with the sampling trigger 

avSStateReg <= "00000";  

else 

case avSStateReg is --gray counter? 

when "00000"=> if(sigSLatchReg='1') then avSStateReg<="00001"; end if; 

when "00001"=> if(sigSLatchReg='1') then avSStateReg<="00011"; end if; 

when "00011"=> if(sigSLatchReg='1') then avSStateReg<="00111"; end if; 

when "00111"=> if(sigSLatchReg='1') then avSStateReg<="01111"; end if; 

when "01111"=> if(sigSLatchReg='1') then avSStateReg<="11111"; end if; 

when "11111"=> if(sigSLatchReg='1') then avSStateReg<="11110"; end if; 

when "11110"=> if(sigSLatchReg='1') then avSStateReg<="11100"; end if; 

when "11100"=> if(sigSLatchReg='1') then avSStateReg<="11000"; end if; 

when "11000"=> if(sigSLatchReg='1') then avSStateReg<="10000"; end if; 

when "10000"=> if(sigSLatchReg='1') then avSStateReg<="00000"; end if; 

when others => avSStateReg<="00000";  

end case; 

end if; 

end if; 

end process; 

 

dfTrigSReg <= '1' when avSStateReg="10000" else '0'; 

 

process(CLK80) 

begin 

if (CLK80'event and CLK80='1') then 

if (sigCLatchReg='1') then 

avSigCReg(0)  

<= sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg; 

for I in 1 to 9 loop 

avSigCReg(I) <= avSigCReg(I-1)  

+ (sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg); 

end loop; 

end if; 

end if; 

end process;  

 

 

process(CLK80) 

begin 

if (CLK80'event and CLK80='1') then 

if (sigSLatchReg='1') then 

avSigSReg(0)  

<= sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg; 

for I in 1 to 9 loop 

avSigSReg(I) <= avSigSReg(I-1)  

+ (sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg); 

end loop; 

end if; 

end if; 

end process;  

 

i dont konw why the designer do this&#65306; avSigCReg(0) <= sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg; 

avSigCReg is is array (0 to 9) of signed(17 downto 0)&#65292; 

I think this code is calculate the average value of 10 signal . 

But I dont understand it ? Thanks for giving your idea.
0 Kudos
13 Replies
Altera_Forum
Honored Contributor II
3,515 Views

Use simulator, waveform says more than unknown code.

0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

Yup, write a testbench and get simulating. 

But you dont really specify exactly what you want? what exactly are you averaging?  

 

Notes on your code:  

- You dont show the whole code, so we cannot see signal declarations 

- WHy have you got a for loop summing together things? 

- This code looks messy 

 

A moving window average is easily acheived with a shift register and an adder tree, with a divider on the end. If the window is 2^n wide, all you need to divide is drop the n LSBs (with a possible rounding stage)
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

 

i dont konw why the designer do this&#65306; avSigCReg(0) <= sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg; 

avSigCReg is is array (0 to 9) of signed(17 downto 0)&#65292; 

I think this code is calculate the average value of 10 signal . 

 

--- Quote End ---  

 

The common arithmetic average of N samples is calculated by summing the samples and then dividing by N. 

Since division by a number which is not power of 2 is resource consuming, you can avoid it by discarding the N factor which is actually not relevant since it's simply a constant multiplier. 

The multiple & sigCReg(13) simply serves for the purpose of sign extending the 14 bit ADC sample to the 18 bit wide sum.
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

Yes&#65292;Thanks for your reply .I have made simulation for this code.It looks like just summing the ten numbers last received from the AD.

0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

Yup, write a testbench and get simulating. 

But you dont really specify exactly what you want? what exactly are you averaging?  

 

Notes on your code:  

- You dont show the whole code, so we cannot see signal declarations 

- WHy have you got a for loop summing together things? 

- This code looks messy 

 

A moving window average is easily acheived with a shift register and an adder tree, with a divider on the end. If the window is 2^n wide, all you need to divide is drop the n LSBs (with a possible rounding stage) 

--- Quote End ---  

 

 

I didn't show the whole code because it's very long.This code is writen by others and I just want to know what exactly it work and use it in my work. I have writen a copy for simulation. I will put it below. 

library ieee; 

use ieee.std_logic_1164.all; 

use ieee.numeric_std.all; 

use ieee.std_logic_unsigned.all; 

entity Averager is 

port(CLK80: in std_logic; 

sigCReg: in signed(13 downto 0); 

SigSReg: in signed(13 downto 0); 

samplingTriggerReg: in std_logic; 

sigCLatchReg: in std_logic; 

sigSLatchReg: in std_logic; 

dfTrigSReg :out std_logic ; 

dftrigCReg: out std_logic; 

WS0: out signed(17 downto 0); 

WS1: out signed(17 downto 0); 

WS2: out signed(17 downto 0); 

WS3: out signed(17 downto 0); 

WS4: out signed(17 downto 0); 

WS5: out signed(17 downto 0); 

WS6: out signed(17 downto 0); 

WS7: out signed(17 downto 0); 

WS8: out signed(17 downto 0); 

WS9: out signed(17 downto 0) 

); 

end Averager; 

architecture Behavioral of Averager is 

signal avCStateReg, avSStateReg: std_logic_vector(4 downto 0):="00000"; 

type avSig is array (0 to 9) of signed(17 downto 0); 

signal avSigSReg,avSigCReg: avSig; 

begin  

process(CLK80) begin 

if(CLK80'event and CLK80='1') then 

if(samplingTriggerReg='1') then -- synchronization with the sampling trigger 

avCStateReg <= "00000";  

else 

case avCStateReg is  

when "00000"=> if(sigCLatchReg='1') then avCStateReg<="00001"; end if; 

when "00001"=> if(sigCLatchReg='1') then avCStateReg<="00011"; end if; 

when "00011"=> if(sigCLatchReg='1') then avCStateReg<="00111"; end if; 

when "00111"=> if(sigCLatchReg='1') then avCStateReg<="01111"; end if; 

when "01111"=> if(sigCLatchReg='1') then avCStateReg<="11111"; end if; 

when "11111"=> if(sigCLatchReg='1') then avCStateReg<="11110"; end if; 

when "11110"=> if(sigCLatchReg='1') then avCStateReg<="11100"; end if; 

when "11100"=> if(sigCLatchReg='1') then avCStateReg<="11000"; end if; 

when "11000"=> if(sigCLatchReg='1') then avCStateReg<="10000"; end if; 

when "10000"=> if(sigCLatchReg='1') then avCStateReg<="00000"; end if; 

when others => avCStateReg<="00000";  

end case; 

end if; 

end if; 

end process; 

 

dfTrigCReg <= '1' when avCStateReg="10000" else '0'; 

 

 

process(CLK80) begin 

if(CLK80'event and CLK80='1') then 

if(samplingTriggerReg='1') then -- synchronization with the sampling trigger 

avSStateReg <= "00000";  

else 

case avSStateReg is --gray counter? 

when "00000"=> if(sigSLatchReg='1') then avSStateReg<="00001"; end if; 

when "00001"=> if(sigSLatchReg='1') then avSStateReg<="00011"; end if; 

when "00011"=> if(sigSLatchReg='1') then avSStateReg<="00111"; end if; 

when "00111"=> if(sigSLatchReg='1') then avSStateReg<="01111"; end if; 

when "01111"=> if(sigSLatchReg='1') then avSStateReg<="11111"; end if; 

when "11111"=> if(sigSLatchReg='1') then avSStateReg<="11110"; end if; 

when "11110"=> if(sigSLatchReg='1') then avSStateReg<="11100"; end if; 

when "11100"=> if(sigSLatchReg='1') then avSStateReg<="11000"; end if; 

when "11000"=> if(sigSLatchReg='1') then avSStateReg<="10000"; end if; 

when "10000"=> if(sigSLatchReg='1') then avSStateReg<="00000"; end if; 

when others => avSStateReg<="00000";  

end case; 

end if; 

end if; 

end process; 

 

dfTrigSReg <= '1' when avSStateReg="10000" else '0'; 

 

process(CLK80) 

begin 

if (CLK80'event and CLK80='1') then 

if (sigCLatchReg='1') then 

avSigCReg(0)<= sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg; 

for I in 1 to 9 loop 

avSigCReg(I) <= avSigCReg(I-1)+ (sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg(13) & sigCReg); 

end loop; 

end if; 

end if; 

end process;  

 

process(CLK80) 

begin 

if (CLK80'event and CLK80='1') then 

if (sigSLatchReg='1') then 

avSigSReg(0)  

<= sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg; 

for I in 1 to 9 loop 

avSigSReg(I) <= avSigSReg(I-1)  

+ (sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg(13) & sigSReg); 

end loop; 

end if; 

end if; 

Ws0<=avSigcReg(0);WS1<=avSigcReg(1);WS2<=avSigcReg(2);WS3<=avSigcReg(3);WS4<=avSigcReg(4); 

Ws5<=avSigcReg(5);WS6<=avSigcReg(6);WS7<=avSigcReg(7);WS8<=avSigcReg(8);WS9<=avSigcReg(9); 

end process;  

end Behavioral; 

 

 

I have simulate it, it looks like adding the ten value last received from the AD. The divider is not occured in this part of code(or just discarding). I wanted to know more about a shift register and an adder tree you have mentioned. 

Thanks for your reply. I'm a new learner so that I don't understand why this code is messy.
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

The common arithmetic average of N samples is calculated by summing the samples and then dividing by N. 

Since division by a number which is not power of 2 is resource consuming, you can avoid it by discarding the N factor which is actually not relevant since it's simply a constant multiplier. 

The multiple & sigCReg(13) simply serves for the purpose of sign extending the 14 bit ADC sample to the 18 bit wide sum. 

--- Quote End ---  

 

Than you for your reply. But whether you mean I can discard the 10(the N in this code),and calculate the turth value when those datas uploaded to the computer.
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

For averaging 2^n samples all you need is discard n LSBs from result of accumulator (as explained in some of above posts). for non power of 2 samples there are some tricks to avoid division e.g. if number of samples is 1000 then average = sum/1000 = sum/1024 * 1.024  

~= sum/1024 *(1+1/64+1/128)  

 

hence average = sum(discard 10 LSBs) + sum(discard 16 LSBs) + sum(discard 17 LSBs)
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

For averaging 2^n samples all you need is discard n LSBs from result of accumulator (as explained in some of above posts). for non power of 2 samples there are some tricks to avoid division e.g. if number of samples is 1000 then average = sum/1000 = sum/1024 * 1.024  

~= sum/1024 *(1+1/64+1/128)  

 

hence average = sum(discard 10 LSBs) + sum(discard 16 LSBs) + sum(discard 17 LSBs) 

--- Quote End ---  

 

Thanks ,Kaz! It's a wonderful ideal !!!
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

For averaging 2^n samples all you need is discard n LSBs from result of accumulator (as explained in some of above posts). for non power of 2 samples there are some tricks to avoid division e.g. if number of samples is 1000 then average = sum/1000 = sum/1024 * 1.024  

~= sum/1024 *(1+1/64+1/128)  

 

hence average = sum(discard 10 LSBs) + sum(discard 16 LSBs) + sum(discard 17 LSBs) 

--- Quote End ---  

 

 

Ok Kaz, but this way you need more system resources, I mean logic gates in fpga or computation time in a programming language.  

In other words you are still implementing some sort of division algorithm. 

I would keep on my idea, which is also the one exploited by the sample code at start of this thread: if you don't mind the x1000 (or whatever) factor you can quietly avoid the division. If you later need to compare this 'average x 1000' with something else, it will be easier to multiply this one x1000 than dividing the average result.
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

Ok Kaz, but this way you need more system resources, I mean logic gates in fpga or computation time in a programming language.  

In other words you are still implementing some sort of division algorithm. 

I would keep on my idea, which is also the one exploited by the sample code at start of this thread: if you don't mind the x1000 (or whatever) factor you can quietly avoid the division. If you later need to compare this 'average x 1000' with something else, it will be easier to multiply this one x1000 than dividing the average result. 

--- Quote End ---  

 

 

Yes I needed two adders (not that bad as a divider).  

I agree you don't need to divide if you want the sum rather than the average but in many cases we do need the average itself over a given time window.
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

hi kaz&#65281; 

 

Maybe I can ask you another VHDL code after this one. The data which is summed will be taken into a digital filter. The code is shown below:------------------- FIR FILTER ------------------ 

 

process(CLK80) 

begin 

if (CLK80'event and CLK80='1') then 

if (DFTrigCReg='1') then 

for I in 0 to firLength-1 loop 

CQRealReg(I) <= avSigCReg(9)(17 downto 4) * DFcoeff(I); 

end loop; 

 

CSRealReg(0) <= CQRealReg(0)(23) & CQRealReg(0)(21 downto 0); 

 

for I in 1 to firLength-1 loop 

CSRealReg(I) <= CSRealReg(I-1) + (CQRealReg(I)(23) & CQRealReg(I)(21 downto 0)); 

end loop; 

end if; --  

end if; -- CLK 

end process; 

I think the DFcoeff is filter coefficient. But why the designer do the process like this" CSRealReg(0) <= CQRealReg(0)(23) & CQRealReg(0)(21 downto 0);"
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

That will be sign extension, ensuring that the slices arrays stay +ve or -ve correctly. 

It reads better if you use the resize() function. 

 

Looking at that code, it wont build the adder tree as I expect it, it just creates FirLength-1 output values (you usually end up with a single output).
0 Kudos
Altera_Forum
Honored Contributor II
3,515 Views

 

--- Quote Start ---  

That will be sign extension, ensuring that the slices arrays stay +ve or -ve correctly. 

It reads better if you use the resize() function. 

 

Looking at that code, it wont build the adder tree as I expect it, it just creates FirLength-1 output values (you usually end up with a single output). 

--- Quote End ---  

 

Yes, but I dont know the resize() function. And maybe the CSRealReg(FirLength-1) is the output which I want . If you're interesting the complete vhdl code you can see it in the attchment, Tricky. Thanks for your help.
0 Kudos
Reply