Forum Discussion
Altera_Forum
Honored Contributor
12 years agocontinuous 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 --- @kaz What if I want to converge to a single value with continuous averaging? Is it possible? As an example if I average first 32 samples and the averaged value used in the next averaged 32 samples. In the end I will converge to some stable ADC value. In this way I will have less fluctuation in my ADC values. --- Quote End --- Depends what you want. if you want running average then we are on it. if you want block average then you can average each block separately. if you then average the averages then it is up to you and your purpose but it only complicates what is basically simple subtract accumulate. - Altera_Forum
Honored Contributor
The filter y(n) = k * y(n-1) + x(n) approximates to average(x) / (1 - k) for 0 < k < 1.
It isn't as good as a rolling average, but is often good enough. - Altera_Forum
Honored Contributor
@dsl
Can you modify my code with your logic? I want to see if I converge to some value after continuous averaging. - Altera_Forum
Honored Contributor
Not quickly - I'm a software engineer, I write assembler and C, not vhdl :-)
- Altera_Forum
Honored Contributor
--- Quote Start --- The filter y(n) = k * y(n-1) + x(n) approximates to average(x) / (1 - k) for 0 < k < 1. It isn't as good as a rolling average, but is often good enough. --- Quote End --- Interesting point. what I found is this: for n taps running average a good approximation is y(i) = a*y(i-1) + (1-a)*x(i); with a = (n-1)/n However this requires two(or one multiplier) plus adder, so I think the true running average is simpler if you can afford the storage. surely for large value of n then your suggestion is much better. Moreover the value (a) is programmable. - Altera_Forum
Honored Contributor
If n is a power of 2 you don't need a multiply - just some shiftsand two adds
- Altera_Forum
Honored Contributor
--- Quote Start --- If n is a power of 2 you don't need a multiply - just some shiftsand two adds --- Quote End --- Yes, in that case we convert: y(n) = a*y(n-1) + (1-a)*x(n) ... two multipliers, one adder ...to y(n) = a*y(n-1) + x(n) -a*x(n) i.e. y(n) = a*(y(n-1) -x(n)) + x(n); ... one multiplier, one subtractor, one adder then (a) can be power of 2 but we get limitations on cutoff point - Altera_Forum
Honored Contributor
@kaz,
I have 2 questions related to the continuous averaging. First question is related to increasing the number of stages. I want to increase the number of stages from 32 to 1000. I am doing this for stabilizing the ADC current values. Do I have to modify the signal lengths in the following way:
The second question is: I was not getting correct values before but now with the following approach I get the correct values. Can you see and tell if the following way looks fine. It is working correctly but Is there a better way to do this? I used the same approach as u told me but in a different way. I need to average in parallel. The code is following:data_in : in std_logic_vector (31 downto 0); type type1 is array (1 to 999) 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');
Many Thanks.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; 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 <= resize(signed(data_in),13) - signed(stage(31)); -- accumulate sum <= sum + sub_result; adc_a_out <= std_logic_vector(sum(16 downto 5)); avg_1 <= '1'; state <= out_2; endif; when out_2 => if done='1' then data_out <= addr1 & bits; 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 <= resize(signed(data_in),13) - signed(stage(31)); -- accumulate sum2 <= sum2 + sub_result2; adc_b_out <= std_logic_vector(sum2(16 downto 5)); avg_2 <= '1'; state <= done_st; when done_st => ack <='1'; state <= idle; when others => state <= idle; end case; end if; end process; - Altera_Forum
Honored Contributor
For a 32 'sample' IRF I'd do:
y(n) = y(n-1) - y(n-1)/32 + x(n) the average is then y(n)/32. - Altera_Forum
Honored Contributor
--- Quote Start --- For a 32 'sample' IRF I'd do: y(n) = y(n-1) - y(n-1)/32 + x(n) the average is then y(n)/32. --- Quote End --- Unfortunately your equation does not match 32 stage running averager at all. values shoot up very high and high frequencies are passed. But it works if: y(n) = y(n-1) - y(n-1)/32 + x(n)/32