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

continuous averaging using VHDL

Altera_Forum
Honored Contributor II
17,134 Views

I have a question related to VHDL programming. I want to calculate the continuous average. My example code is: 

 

process (clk, reset) begin if (reset = '1') then state<=idle; out-val=0; elsif(rising_edge(clk)) then case state is when idle => if req='1' then state= out-1; end if; when out-1 => if done='1' then out-val<=data-in (11 downto 0) state <= done-st; endif; when done-st => ack <='1'; state <= idle; when others => state <= idle; end case; end if; end process;  

 

On every positive edge of clock, the value of "out-val" changes. I want to continuously take the average of "out-val". I want to take average of 32 values continuously. Is there a way where I can take average of 32 values continuously till the clock is running. Kindly let me know how can I do that. You can modify the above code as well. 

Many Thanks,
0 Kudos
90 Replies
Altera_Forum
Honored Contributor II
1,683 Views

check your count becomes zero 

check avg
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

check your count becomes zero 

check avg 

--- Quote End ---  

 

 

@kaz 

 

the counter value becomes zero and I get the adc value on the FPGA very late. I think the process is very slow because of 1024 samples. Is there a way to make it fast?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

The samples should end up in a memory block - with read and write pointers.

0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

@kaz 

 

the counter value becomes zero and I get the adc value on the FPGA very late. I think the process is very slow because of 1024 samples. Is there a way to make it fast? 

--- Quote End ---  

 

 

1/1024 is the update rate of avg, this then averaged at this slow rate.  

That is you wanted and shouldn't be a problem , not even in simulation. What is ADC speed then?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

1/1024 is the update rate of avg, this then averaged at this slow rate.  

That is you wanted and shouldn't be a problem , not even in simulation. What is ADC speed then? 

--- Quote End ---  

 

 

My ADC captures value every 312/20 KHz i-e 15.6 KHz.
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

 

Two questions. The approach that I was using before for 32 samples, I increased that to 100 samples. I did following changes in the code: 

 

data_in : in std_logic_vector (99 downto 0); type type1 is array (1 to 99) of std_logic_vector(11 downto 0); signal stage: type1 := (others => (others => '0')); signal sub_result: signed(12 downto 0) := (others => '0'); signal sum: signed(19 downto 0) := (others => '0'); process (clk, reset) begin if (reset = '1') then state<=idle; out_val=0; out_val_2 <= 0; elsif(rising_edge(clk)) then case state is when idle => if req='1' then state= out_1; end if; when out_1 => if done='1' then data_out <= addr0 & bits; stage(1) <= data_in(11 downto 0); for i in 2 to 99 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= resize(signed(data_in),13) - signed(stage(99)); -- accumulate sum <= sum + sub_result; adc_a_out <= std_logic_vector(sum(19 downto 8)); avg_1 <= '1'; state <= out_2; endif; end case; end if; end process; 

 

Can you tell if the number of bits for sum and sub_result are correct for 100 samples? 

 

2nd question is related to the block average. I changed the 1024 samples to 32 samples and then averaging 5 blocks. 

 

signal counter : integer 0 to 31 := 0; signal data_in_d : signed(11 downto 0) := (others => '0'); signal sum: signed(16 downto 0) := (others => '0); signal avg : std_logic_vector (11 downto 0); type type1 is array (1 to 3) of std_logic_vector(11 downto 0); signal stage: type1 := (others => (others => '0')); signal sub_result: signed(12 downto 0) := (others => '0'); signal sum_new: signed(16 downto 0) := (others => '0'); process (clk, reset) begin if (reset = '1') then out_val=0; elsif(rising_edge(clk)) then case state is when out_1 => if done='1' then data_out <= addr0 & bits; counter <= counter + 1; data_in_d <= signed(data_in); if counter /= 0 then sum <= sum + data_in_d; else sum <= (others => '0'); avg <= std_logic_vector(sum(16 downto 5)); stage(1) <= avg(11 downto 0); for i in 2 to 4 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= resize(signed(avg),13) - signed(stage(4)); -- accumulate sum_new <= sum_new + sub_result; adc_a_out <= std_logic_vector(sum_new(16 downto 5)); end if; state <= out_2; endif; end process; 

 

Is the number of bits for sum and sum assignment to avg is correct?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

The principle is that sum width must not overflow so you are flexible here and depends on nature of your signal. 

for 100 samples you can't divide easily (but you may just compare sum with sum without division). if you use 128 samples then you discard 7 bits from sum to divide it by 128. 

for 5 samples again you can't divide easily, make it 8 samples then discard 3 bits from sum
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

Got the point. Thanks much. 

Another question: Why did we make the size of subtractor "sub_result" 13 bit? Can't we make it 11 bit?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

@kaz 

Another question: Why did we make the size of subtractor "sub_result" 13 bit? Can't we make it 11 bit? 

--- Quote End ---  

 

 

if data_in is + and last stage is - then both samples are added in effect requiring one more bit
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

 

Thanks for your answer above. Actually everything is working good for me. Now there are only two issues. The first approach that I used which is continuous averaging of example 256 samples. The ''adc_a_out'' value that I receive on my GUI increments slowly. As an example, if I am expecting value 100mA, My GUI shows 4mA, 8mA, 15mA,...... and then finally after 2 minutes I get stable 100mA value. I want to see the 100mA directly on my GUI from 'adc_a_out' instead of increment values and stabilizing after sometime. Another question is that, Can I somehow make this process fast so that I don't have to wait for 3 minutes for receiving stable 100 mA from adc_a_out. I am copying the code again that I used for testing. The clock 'clk' in the digital design below is 20 MHz. The clock for receiving ADC values on the FPGA board is 15 KHz. 

 

data_in : in std_logic_vector (31 downto 0); type type1 is array (1 to 255) of std_logic_vector(11 downto 0); signal stage: type1 := (others => (others => '0')); signal sub_result: signed(12 downto 0) := (others => '0'); signal sum: signed(19 downto 0) := (others => '0'); process (clk, reset) begin if (reset = '1') then out_val=0; elsif(rising_edge(clk)) then case state is when out_1 => if done='1' then data_out <= addr0 & bits; stage(1) <= data_in(11 downto 0); for i in 2 to 255 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= resize(signed(data_in),13) - signed(stage(255)); -- accumulate sum <= sum + sub_result; adc_a_out <= std_logic_vector(sum(19 downto 8)); state <= out_2; endif; end process;
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

Your code looks ok. Delay of 2 minutes is too much on 15KHz ADC signal. Either your adc doesn't build up that fast or your state changes and doesn't track adc correctly

0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

For getting the stable value directly instead of increasing slowly, I did the following change in the code (The change is only when reset = 1).  

 

data_in : in std_logic_vector (31 downto 0); type type1 is array (1 to 255) of std_logic_vector(11 downto 0); signal stage: type1 := (others => (others => '0')); signal sub_result: signed(12 downto 0) := (others => '0'); signal sum: signed(19 downto 0) := (others => '0'); process (clk, reset) begin if (reset = '1') then out_val=0; stage <= (others => data_in(11 downto 0)); sum <= resize(255 * signed(data_in(11 downto 0)), sum'length); elsif(rising_edge(clk)) then case state is when out_1 => if done='1' then data_out <= addr0 & bits; stage(1) <= data_in(11 downto 0); for i in 2 to 255 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= resize(signed(data_in),13) - signed(stage(255)); -- accumulate sum <= sum + sub_result; adc_a_out <= std_logic_vector(sum(19 downto 8)); state <= out_2; endif; end process; 

 

Do you think it is correct?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

@kaz 

For getting the stable value directly instead of increasing slowly, I did the following change in the code (The change is only when reset = 1).  

Do you think it is correct? 

--- Quote End ---  

 

 

That is naughty. You are faking the initial value of sum using 255*sum at reset.
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

That is naughty. You are faking the initial value of sum using 255*sum at reset. 

--- Quote End ---  

 

 

What else should I do in order to achieve for example 100mA instead of 4 mA, 8 mA, 15 mA,.......100mA. I need stable value directly. What else can I do in the code?
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

What else should I do in order to achieve for example 100mA instead of 4 mA, 8 mA, 15 mA,.......100mA. I need stable value directly. What else can I do in the code? 

--- Quote End ---  

 

 

your running average should work. Are you sampling eacg adc sample through it. What is that done = '1' for and do you stay in state out_1 enough to do the job. Your adc data rate of 15KHz should be averaged sooner unless it starts low.
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

 

'done' is coming from the SPI master block indicating valid transfer. Yes I am sampling each adc sample through it. 

Also as I told you before there are two outputs of ADC. i-e 'adc_a_out' and 'adc_b_out' 12 bit each. In the end I do the 'and' of both of these outputs and I have 24 bit value of ADC and then send to GUI via USB interface.
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

 

--- Quote Start ---  

@kaz 

 

'done' is coming from the SPI master block indicating valid transfer. Yes I am sampling each adc sample through it. 

Also as I told you before there are two outputs of ADC. i-e 'adc_a_out' and 'adc_b_out' 12 bit each. In the end I do the 'and' of both of these outputs and I have 24 bit value of ADC and then send to GUI via USB interface. 

--- Quote End ---  

 

 

I don't get it. Do you have one or two adc. if two independant adc then why you AND (or possibly you mean concatenate them) into 24 bit. 

 

The proper value of adc should enter the filter. If the two values are one adc sample then you should pass that into the filter.
0 Kudos
Altera_Forum
Honored Contributor II
1,683 Views

@kaz 

Yes I mean to concatenate them. I have two ADCs. Each ADC has two 12 bit inputs that captures the value. One ADC is for current measurement and the other for voltage measurement. The voltage measurement ADC is fine and I don't need filter for that. I need the filter for current measurement ADC. I concatenate the four outputs (two from first ADC and two outputs from second ADC) into 48 bits. I am doing the 'and' or concatenate on the top level. Then I am passing the concatenated value to the GUI via USB interface.
0 Kudos
Altera_Forum
Honored Contributor II
1,682 Views

So they are two independent samples, each one from its own adc then why concatenate them as 24 bits value? what does this 24 bit value represent then?

0 Kudos
Altera_Forum
Honored Contributor II
1,682 Views

I updated the previous post. I am posting it again. 

@kaz 

Yes I mean to concatenate them. I have two ADCs. Each ADC has two 12 bit inputs that captures the value. One ADC is for current measurement and the other for voltage measurement. The voltage measurement ADC is fine and I don't need filter for that. I need the filter for current measurement ADC. I concatenate the four outputs (two from first ADC and two outputs from second ADC) into 48 bits. I am doing the 'and' or concatenate on the top level. Then I am passing the concatenated value to the GUI via USB interface. These 48 bits value represents the Current and voltage.
0 Kudos
Altera_Forum
Honored Contributor II
1,682 Views

"I have two ADCs, each ADC has 12 bit inputs (you mean outputs)" 

"two outputs from first ADC..."??? 

what is the sample width of your current ADC? is it 12 bits or 24 bits?
0 Kudos
Reply