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

continuous averaging using VHDL

Altera_Forum
Honored Contributor II
12,519 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,773 Views

 

--- Quote Start ---  

"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? 

--- Quote End ---  

 

 

Yes I mean two 12 bit outputs 

Its 12 bits.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

is it possible to know the ADC device you are using just to make up my mind why it is 12 bits and 24 bits.

0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

is it possible to know the ADC device you are using just to make up my mind why it is 12 bits and 24 bits. 

--- Quote End ---  

 

 

Yes. I am using ADC122S021
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

This device has figures for Fsclk & Fs separately. 

I understand that min Fs is 50Ksps and max Fs is 200Ksps. The Fsclk has then to be fast enough for 12 bits (in fact 16 times as Fs) i.e. Fsclk(min) = .8MHz 

and 3.2MHz(max). 

 

Yet you are using Fsclk of 15KHz i.e. Fs = 15KHz/16 = .9KHz appart from violating device spec. 

 

Am I right?
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

This device has figures for Fsclk & Fs separately. 

I understand that min Fs is 50Ksps and max Fs is 200Ksps. The Fsclk has then to be fast enough for 12 bits (in fact 16 times as Fs) i.e. Fsclk(min) = .8MHz 

and 3.2MHz(max). 

 

Yet you are using Fsclk of 15KHz i.e. Fs = 15KHz/16 = .9KHz appart from violating device spec. 

 

Am I right? 

--- Quote End ---  

 

 

The FSclk is 312KHz which means Fs= 312/16=19.5 KHz
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

The FSclk is 312KHz which means Fs= 312/16=19.5 KHz 

--- Quote End ---  

 

 

OK assuming 19.5Ksps is not violating spec then I don't see why you shouldn't get the mean quickly. Your accumulator will settle after 256 samples i.e. within msec(you have 19.5Ksps) 

You better check in signaltap or simulation what is causing this delay. It should be easy as you can check sum and avg all the way through. 

your accummulator bitwidth of 20 bits is just right (12 bits + 8bits = 20bits) so there is no overflow.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

OK assuming 19.5Ksps is not violating spec then I don't see why you shouldn't get the mean quickly. Your accumulator will settle after 256 samples i.e. within msec(you have 19.5Ksps) 

You better check in signaltap or simulation what is causing this delay. It should be easy as you can check sum and avg all the way through. 

your accummulator bitwidth of 20 bits is just right (12 bits + 8bits = 20bits) so there is no overflow. 

--- Quote End ---  

 

 

Ok. I will check in the simulation what is causing the delay. But one thing I am confused is about those slowly incrementing values. I don't know why I see like 4mA, 8 mA, 16mA,,..... finally stable value of 100mA. I don't know why it is not just showing me 100mA directly.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

Ok. I will check in the simulation what is causing the delay. But one thing I am confused is about those slowly incrementing values. I don't know why I see like 4mA, 8 mA, 16mA,,..... finally stable value of 100mA. I don't know why it is not just showing me 100mA directly. 

--- Quote End ---  

 

 

If your adc data is a constant (or so) then your accumulator (plus division by 256) will build up from zero gradually then settle at the constant value when sample 255 arrives from stage 255 i.e. it should be within msec not second. during this initial time there is subtraction from zero and so the summed up total divided by 2^8 will be less than constant until all 256 samples are added and divided by 2^8 to equal the constant. Thereafter any new sample arrival is added but last one subtracted leading to same constant.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

If your adc data is a constant (or so) then your accumulator (plus division by 256) will build up from zero gradually then settle at the constant value when sample 255 arrives from stage 255 i.e. it should be within msec not second. during this initial time there is subtraction from zero and so the summed up total divided by 2^8 will be less than constant until all 256 samples are added and divided by 2^8 to equal the constant. Thereafter any new sample arrival is added but last one subtracted leading to same constant. 

--- Quote End ---  

 

 

@kaz 

I don't see anything stupid in the simulation. No idea why I am getting this delay now.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

@kaz 

I don't see anything stupid in the simulation. No idea why I am getting this delay now. 

--- Quote End ---  

 

 

I take it that there is no such delay in simulation but in hardware. Did you see sum building up soon and avg taking values. In that case revise your design and use signaltap. 

Check your clocking scheme. Your adc samples should be sampled into filter at 19.5KHz. since your clock is 312KHz I therefore assume your done = '1' is enabling clock at 19.5KHz.
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

@kaz 

Yes I can see the sum building up soon and avg taking values. One observation during hardware testing is when I increase the number of samples from 128 to 256, I receive the ADC current values slowly. The less the number of samples, the faster I get the averaged values on GUI. But the values I receive is always like 4mA, 8mA, 15mA, 25mA....., 100mA, 101mA, 102mA, 100mA, 99mA... I want to recieve only in the small range of 10mA eg.. between 95mA and 105mA. Is there a way that I can discard values such as 4mA, 8mA,.....90mA and recieve the value when it comes in range between 95mA and 105mA. How can I use signaltap in my code?
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

@kaz 

Yes I can see the sum building up soon and avg taking values. One observation during hardware testing is when I increase the number of samples from 128 to 256, I receive the ADC current values slowly. The less the number of samples, the faster I get the averaged values on GUI. But the values I receive is always like 4mA, 8mA, 15mA, 25mA....., 100mA, 101mA, 102mA, 100mA, 99mA... I want to recieve only in the small range of 10mA eg.. between 95mA and 105mA. Is there a way that I can discard values such as 4mA, 8mA,.....90mA and recieve the value when it comes in range between 95mA and 105mA. How can I use signaltap in my code? 

--- Quote End ---  

 

 

For the issue of not receiving initial build up values until it settles, yes you can do that readily: 

 

with avg and avg_final starting at zero(at reset) 

if avg > 95 then 

avg_final <= avg; -- update 

end if; 

 

signaltap does not require code change but is a tool that you need to learn and capture data from any node for display or saving into files. It is added to project through the quartus before compilation. 

 

I assume your adc signal is a constant value but remember that adc signal may start with +/- values due to noise or step response and thus may average slowly up
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

For the issue of not receiving initial build up values until it settles, yes you can do that readily: 

 

with avg and avg_final starting at zero(at reset) 

if avg > 95 then 

avg_final <= avg; -- update 

end if; 

 

signaltap does not require code change but is a tool that you need to learn and capture data from any node for display or saving into files. It is added to project through the quartus before compilation. 

 

I assume your adc signal is a constant value but remember that adc signal may start with +/- values due to noise or step response and thus may average slowly up 

--- Quote End ---  

 

 

@kaz 

I don't want to write specific value 95 because the range is not always 95mA to 105mA. It should be generalized because 95mA to 105mA is for specific voltage that I set in DAC. How can make it generalized? 

 

Also, I am using the code in a different way and I am getting the values quickly but the values coming out are wrong. I am using the code as follows: 

 

--use_average.vhdl file library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity use_average is port ( clock: in std_logic; reset: in std_logic; channel_1_sample: in std_logic_vector(11 downto 0); channel_2_sample: in std_logic_vector(11 downto 0); slv_value1 : out std_logic_vector (11 downto 0); slv_value2 : out std_logic_vector (11 downto 0) ); end; architecture rtl of use_average is signal average_1, average_2: std_logic_vector(11 downto 0); begin channel_1: entity work.average port map( sample => channel_1_sample, average => average_1, clock => clock, reset => reset ); channel_2: entity work.average port map( sample => channel_2_sample, average => average_2, clock => clock, reset => reset ); slv_value1 <= average_1; slv_value2 <= average_2; end; 

 

The average block is as follows: 

 

--average.vhd library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity average is port ( sample: in std_logic_vector(11 downto 0); average: out std_logic_vector(11 downto 0); clock: in std_logic; reset: in std_logic ); end; architecture rtl of average is 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'); begin process (clock, reset) begin if (reset = '1') then average <= (others => '0'); elsif (rising_edge(clock)) then stage(1) <= sample(11 downto 0); for i in 2 to 255 loop stage(i) <= stage(i-1); end loop; sub_result <= resize(signed(sample),13) - signed(stage(255)); sum <= sum + sub_result; average <= std_logic_vector(sum(19 downto 8)); end if; end process; end; 

 

In the adc top level block, the use_average block is used as follows: 

 

component use_average is port ( clock: in std_logic; reset: in std_logic; channel_1_sample: in std_logic_vector(11 downto 0); channel_2_sample: in std_logic_vector(11 downto 0); slv_value1 : out std_logic_vector (11 downto 0); slv_value2 : out std_logic_vector (11 downto 0) ); end component; inst_average : use_average port map ( clock => clk, reset => reset, channel_1_sample => adc_a_1_temp, channel_2_sample => adc_b_1_temp, slv_value1 => slv_value1, slv_value2 => slv_value2 ); 

adc_a_1_temp and adc_b_1_temp are the output signals coming from the adc block i-e: 

 

data_in : in std_logic_vector (31 downto 0); process (clk, reset) begin if (reset = '1') then out_val=0; adc_a_1_temp = 0; adc_b_1_temp = 0; elsif(rising_edge(clk)) then case state is when out_1 => if done='1' then data_out <= addr0 & bits; adc_a_1_temp <= data_in(11 downto 0); state <= out_2; when out_2 => adc_b_1_temp <= data_in(11 downto 0); state <= idle; endif; end process 

 

Is it okay If I use the code in the above way? Kindly let me know. 

Thanks
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

It looks ok to me. 

Can you do describe what wrong is? do you have a model to check against or do you do that manually. 

 

above all is your adc data correctly entering the filters. 

 

here is a model for running average 

 

%(n) stage running average, implementation model %delay input n stages, %subtract last stage from current input %accumulate result and discard LSBs clear all; v = 2^16; %vector length n = 256; %filter stages data = round(2^10*randn(1,v)); data2 = data - ; data3 = cumsum(); result = floor(data3/n); %test it using direct computation of mean of every n samples data = ; avg = zeros(1,v); for i = 1:v avg(i) = floor(mean(data(i:i+n-1))); end figure;hold; plot(result); plot(avg,'r--'); figure; plot(result(1:end-1) - avg);
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

It looks ok to me. 

Can you do describe what wrong is? do you have a model to check against or do you do that manually. 

 

above all is your adc data correctly entering the filters. 

 

here is a model for running average 

 

%(n) stage running average, implementation model %delay input n stages, %subtract last stage from current input %accumulate result and discard LSBs clear all; v = 2^16; %vector length n = 256; %filter stages data = round(2^10*randn(1,v)); data2 = data - ; data3 = cumsum(); result = floor(data3/n); %test it using direct computation of mean of every n samples data = ; avg = zeros(1,v); for i = 1:v avg(i) = floor(mean(data(i:i+n-1))); end figure;hold; plot(result); plot(avg,'r--'); figure; plot(result(1:end-1) - avg);  

--- Quote End ---  

 

 

Sorry, I was making small mistake in wiring the signals. But now I get the correct values with the above approach. Now the issue comes in the variation. Now I get the values eg. 95mA, 100mA, 105mA,... then all of a sudden it jumps to higher value like 140mA and then all of a sudden it comes to 80mA. I am receiving the values quickly now with the approach I wrote earlier, but the variation is a lot. Is there a way I can decrease the variation?
0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

Are you waiting long enough for the A/D converter to settle/convert before reading the value?

0 Kudos
Altera_Forum
Honored Contributor II
1,773 Views

 

--- Quote Start ---  

Sorry, I was making small mistake in wiring the signals. But now I get the correct values with the above approach. Now the issue comes in the variation. Now I get the values eg. 95mA, 100mA, 105mA,... then all of a sudden it jumps to higher value like 140mA and then all of a sudden it comes to 80mA. I am receiving the values quickly now with the approach I wrote earlier, but the variation is a lot. Is there a way I can decrease the variation? 

--- Quote End ---  

 

 

either your adc signal is like that or your wiring is wrong or your conversion to mA is wrong. If adc signal is like that then your filter is doing the job. 

you can reduce variation by using higher order than 256.
0 Kudos
Altera_Forum
Honored Contributor II
1,772 Views

 

--- Quote Start ---  

Are you waiting long enough for the A/D converter to settle/convert before reading the value? 

--- Quote End ---  

 

 

Yes I am. I am sending the opcode for getting ADC value after every 2 seconds.
0 Kudos
Altera_Forum
Honored Contributor II
1,772 Views

 

--- Quote Start ---  

either your adc signal is like that or your wiring is wrong or your conversion to mA is wrong. If adc signal is like that then your filter is doing the job. 

you can reduce variation by using higher order than 256. 

--- Quote End ---  

 

 

I showed you in my above code how my signals are wired. Do you think they are wrong? 

slv_value1 => slv_value1, slv_value2 => slv_value2  

The concatenation of above signals are the outputs that I get on the GUI. 

Also I changed 256 to 512 but still there is variation. There is not much difference. adc_a_1_temp and adc_b_1_temp are going into the average block in my code.
0 Kudos
Altera_Forum
Honored Contributor II
1,772 Views

 

--- Quote Start ---  

I showed you in my above code how my signals are wired. Do you think they are wrong? 

slv_value1 => slv_value1, slv_value2 => slv_value2  

The concatenation of above signals are the outputs that I get on the GUI. 

Also I changed 256 to 512 but still there is variation. There is not much difference. adc_a_1_temp and adc_b_1_temp are going into the average block in my code.  

--- Quote End ---  

 

 

I sense something wrong with your interpretation of that concatenation. Reading back your previous posts you talk about two adcs one for voltage(does not need filter) and one for current(needs filter) yet you are filtering two adcs and there seems to be four adcs in total. each adc is 12 bits then you talk about concatenating two 12 bits into 24 bits for GUI. 

 

Do you have one adc for current(not voltage) or do you have two adcs for current(not voltage). If so why do you concatenate them. Is it just for passing purpose and that GUI will read ech 12 bits value separately or will it read the 24 bits as one value? 

 

I think you need to clear this confusion.
0 Kudos
Altera_Forum
Honored Contributor II
1,772 Views

 

--- Quote Start ---  

I sense something wrong with your interpretation of that concatenation. Reading back your previous posts you talk about two adcs one for voltage(does not need filter) and one for current(needs filter) yet you are filtering two adcs and there seems to be four adcs in total. each adc is 12 bits then you talk about concatenating two 12 bits into 24 bits for GUI. 

 

Do you have one adc for current(not voltage) or do you have two adcs for current(not voltage). If so why do you concatenate them. Is it just for passing purpose and that GUI will read ech 12 bits value separately or will it read the 24 bits as one value? 

 

I think you need to clear this confusion. 

--- Quote End ---  

 

 

@kaz, 

 

I have figured it out that my average block was not running at all because I was running it at 20MHz and the done signal coming from SPI block is running on 78KHz which means I get the next data_in after every 78KHz. I am now running my average block on CS (78kHz) coming from spi master instead of normal clock of 20MHz. Now I am getting the result like before i-e 10mA, 20mA, 40mA,......100mA and the value gets stable after that. I am not sure but I think I need to further divide down the CS to 39KHz to get the 100mA directly. Am I right?
0 Kudos
Reply