- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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,
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- 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, --- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I exactly still don't understand what you mean. Can you write down the code if it is possible?
ManY Thanks- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@kaz
Just as an example, I am doing continuous averaging for 4 values. Can you check if my approach is correct.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;
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- @kaz Just as an example, I am doing continuous averaging for 4 values. Can you check if my approach is correct.
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;
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 example -- 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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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:
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;
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@tricky
Sorry that was a mistake. You are right. I mean ('0' & data_in(11 downto 0); Sorry for the confusion. Can you tell me why I am not getting correct ADC values? I used the approach that was given to me in the previous comment by @kaz- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If the direct ADC values are incorrect, isnt this something for you to Debug? it would be easy to test this code does a rolling average in a simple testbench (you just pass a set of known values into the data_in port) so you can ensure this works before debugging any upstream problems.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- @tricky Sorry that was a mistake. You are right. I mean ('0' & data_in(11 downto 0); Sorry for the confusion. Can you tell me why I am not getting correct ADC values? I used the approach that was given to me in the previous comment by @kaz --- Quote End --- you should not put '0' unless it is unsigned but your computation is signed. This will give wrong results. if your data is 12 bits then use less bits(subtractor needs 13 bits, sum needs 18 bits). you are wasting double resource for two cases. You can use one computation section for both switching between them at input to delay section. setting data type to signed at delay stages as Tricky suggested is an option but I believe doesn't make life any easier.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
An alternative is to use an 'infinite response filter' instead of a true average. This gives more weight to recent data, but is easier to calculate since it doesn't require all the old values be stored.
Basically calculate 'new_irf = old_irf * 31/32 + sample'.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@kaz
If I dont put '0', I get the following error. Should I reduce subtractor bits? Error (10344): VHDL expression error at adc_cntrl.vhd(160): expression has 12 elements, but must have 13 elements. Can you tell me how can I use one computation section for both switching between them at input to delay section? Can you modify my code? Many Thanks- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@dsl
Can you modify my code with your approach?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- @kaz If I dont put '0', I get the following error. Should I reduce subtractor bits? Error (10344): VHDL expression error at adc_cntrl.vhd(160): expression has 12 elements, but must have 13 elements. --- Quote End --- sub_result <= resize(signed(data_in),13) - signed(stage(31)); if you are not averaging both ADC data in parallel then you can switch between them at signal stage:
if avg_1 then
stage(1) <= adc1;
elsif avg_2 then
stage(1) <= adc2;
end if;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- An alternative is to use an 'infinite response filter' instead of a true average. This gives more weight to recent data, but is easier to calculate since it doesn't require all the old values be stored. Basically calculate 'new_irf = old_irf * 31/32 + sample'. --- Quote End --- you are using an integrator of equation: y(n) = 31/32*y(n-1) + x(n); This has a different response from running average filter and is not functionally equivalent. The post is focused on running average. If it is ok then why not just use: y(n) = y(n-1) + x(n) i.e. just an accumulator: sum <= sum + data_in;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@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.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@kaz
I am averaging both the adc data in parallel. That is why I used 2 computations.- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page