Forum Discussion
continuous averaging using VHDL
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,90 Replies
- Altera_Forum
Honored Contributor
--- Quote Start --- I have a question related to VHDL programming. I want to calculate the continuous average. My example code is:
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, --- Quote End --- first you nee to correct your syntax (don't use dash but underscore) For running average filter, the easiest way is delay input through 32 stages. subtract last stage from input and accumulate result.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; - Altera_Forum
Honored Contributor
Actually I used underscore in my original code. I don't know why did I write 'out-1' here. Its 'out_1' Sorry for the confusion. Can you describe with an example how to do continuous averaging.
- Altera_Forum
Honored Contributor
--- Quote Start --- Actually I used underscore in my original code. I don't know why did I write 'out-1' here. Its 'out_1' Sorry for the confusion. Can you describe with an example how to do continuous averaging. --- Quote End --- running average: input =>=>=>...32 stages -----------------> subtract stage 32 from current input put the subtractor at end of delay pipe to subtract last stage from current input then take the result of subtraction into an accumulator (feedback adder with one register). truncate the accumulator sum as suitable. - Altera_Forum
Honored Contributor
--- Quote Start --- then take the result of subtraction into an accumulator (feedback adder with one register). truncate the accumulator sum as suitable. --- Quote End --- discard 5 LSBs from accumulator result. The first initial 31 samples will not be correct but the stream will then get right. - Altera_Forum
Honored Contributor
I exactly still don't understand what you mean. Can you write down the code if it is possible?
ManY Thanks - Altera_Forum
Honored Contributor
--- Quote Start --- I exactly still don't understand what you mean. Can you write down the code if it is possible? ManY Thanks --- Quote End --- writing code is no small job. attached diagram should be clear. - Altera_Forum
Honored Contributor
@kaz
Just as an example, I am doing continuous averaging for 4 values. Can you check if my approach is correct.
sum is the output average value. The above code works if I have unsigned numbers. But I want to average the std_logic_vector. The data_in is defined as: data_in: in std_logic_vector (11 downto 0); Kindly help me in solving this issue. Please modify the above code so that I can get continuous averaging values for vector 'out_val'. Many Thanks.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); i_valid <=1; state <= done_st; endif; when done_st => ack <='1'; state <= idle; when others => state <= idle; end case; end if; end process; process begin wait until rising_edge(clk); valid1 <= i_valid; o_valid <= valid1; end process -- i_valid is control bit and enables when input data is valid process begin wait until rising_edge(clk); if reset = ’1’ then idx <= "0001"; elseif valid1 = ’1’ then idx <= idx rol 1; end if; end if; end process; process begin wait until rising_edge(clk); for i in 3 downto 0 loop if (i_valid = ’1’) and (idx(i) = ’1’) then M(i) <= out_val; end if; end loop; end process; mem_out <= M(0) when idx(0) = ’1’else M(1) when idx(1) = ’1’else M(2) when idx(2) = ’1’else M(3); add_sub <= sum - mem_out when valid1 = ’1’ else sum + mem_out; process begin wait until rising_edge(clk); if i_valid = ’1’ or valid1 = ’1’ then sum <= add_sub; end if; end process; - Altera_Forum
Honored Contributor
--- Quote Start --- @kaz Just as an example, I am doing continuous averaging for 4 values. Can you check if my approach is correct.
sum is the output average value. The above code works if I have unsigned numbers. But I want to average the std_logic_vector. The data_in is defined as: data_in: in std_logic_vector (11 downto 0); Kindly help me in solving this issue. Please modify the above code so that I can get continuous averaging values for vector 'out_val'. Many Thanks. --- Quote End --- I don't see how your approach works. If it is me I will just follow the diagram I posted earlier. for exampleprocess (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); i_valid <=1; state <= done_st; endif; when done_st => ack <='1'; state <= idle; when others => state <= idle; end case; end if; end process; process begin wait until rising_edge(clk); valid1 <= i_valid; o_valid <= valid1; end process -- i_valid is control bit and enables when input data is valid process begin wait until rising_edge(clk); if reset = ’1’ then idx <= "0001"; elseif valid1 = ’1’ then idx <= idx rol 1; end if; end if; end process; process begin wait until rising_edge(clk); for i in 3 downto 0 loop if (i_valid = ’1’) and (idx(i) = ’1’) then M(i) <= out_val; end if; end loop; end process; mem_out <= M(0) when idx(0) = ’1’else M(1) when idx(1) = ’1’else M(2) when idx(2) = ’1’else M(3); add_sub <= sum - mem_out when valid1 = ’1’ else sum + mem_out; process begin wait until rising_edge(clk); if i_valid = ’1’ or valid1 = ’1’ then sum <= add_sub; end if; end process;-- not tested -- input data_in & output assumed std_logic_vector(15 downto 0); type type1 is array (1 to 31) of std_logic_vector(15 downto 0); signal stage: type1 := (others => (others => '0')); signal sub_result: signed(16 downto 0) := (others => '0'); signal sum: signed(20 downto 0) := (others => '0'); -- delay input 31 stages process begin wait until clock = '1'; stage(1) <= data_in; for i in 2 to 31 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= signed(data_in) - signed(stage(31)); -- accumulate sum <= sum + sub_result; output <= std_logic_vector(sum(20 downto 5)); end process; - Altera_Forum
Honored Contributor
Your approach didn't work for me. I checked the output on the FPGA but it didn't work for me. Basically I am trying to stabilize the ADC output values. That is why I am averaging the incoming data or captured data with ADC. out_val and out_val_2 are the 12 bit ADC outputs. I'll show how I used your approach below. Kindly correct me if I am wrong:
I measure the adc values (current and voltage) "adc_a_out and adc_b_out" after using the above approach and I get incorrect values. Kindly let me know where I am doing wrong.data_in : in std_logic_vector (31 downto 0); type type1 is array (1 to 31) 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(16 downto 0) := (others => '0'); signal stage2: type1 := (others => (others => '0')); signal sub_result2: signed(12 downto 0) := (others => '0'); signal sum2: signed(16 downto 0) := (others => '0'); process (clk, reset) begin if (reset = '1') then state<=idle; out_val=0; out_val_2 <= 0; avg_1 <= 0; avg_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; out_val<=data_in (11 downto 0); avg_1 <= '1'; state <= out_2; endif; when out_2 => if done='1' then data_out <= addr1 & bits; out_val_2<=data_in (11 downto 0); avg_2 <= '1'; state <= done_st; when done_st => ack <='1'; state <= idle; when others => state <= idle; end case; end if; end process; --Then comes your approach -- delay input 31 stages adc_a_avg : process begin wait until clk = '1'; if avg_1 = '1' then stage(1) <= data_in(11 downto 0); for i in 2 to 31 loop stage(i) <= stage(i-1); end loop; -- subtract last stage from input sub_result <= signed(data_in(11 downto 0) & '0') - signed(stage(31)); -- I had to append 0 because I was getting error if I don't put it. -- accumulate sum <= sum + sub_result; adc_a_out <= std_logic_vector(sum(16 downto 5)); end if; end process adc_a_avg; adc_b_avg : process begin wait until clk = '1'; if avg_2 = '1' then stage2(1) <= data_in(11 downto 0); for i in 2 to 31 loop stage2(i) <= stage2(i-1); end loop; -- subtract last stage from input sub_result2 <= signed(data_in(11 downto 0) & '0') - signed(stage2(31)); -- accumulate sum2 <= sum2 + sub_result2; adc_b_out <= std_logic_vector(sum2(16 downto 5)); end if; end process adc_b_avg; - Altera_Forum
Honored Contributor
Couple of comments:
Why are you appending '0' on the LSB? thats like a multiply by 2, and as it is signed, it then uses the MSB as the sign bit. I think you mean: ('0' & data_in(11 downto 0); Unless data_in is signed, then you need: (data_in(11) & data_in(11 downto 0)); And as a general comment: Why is type1 an array of std_logic_vector? why not make your life easier and make it an array of signed, then you dont need all the type conversions.