Search code examples
vhdlfpgaxilinxxilinx-isedigital-logic

Arithmetic mean of a register in vhdl


For a project I am currently working on, I am trying to take some inputs, store them in a register then find the arithmetic mean of the register. All of my inputs are 24-bits long. My registers are 4-inputs long therefore I simply remove the last 3-digits of the least-significant bits while dividing them by 4 in order to calculate the arithmetic mean, then simply add them.

mean is my register(95 downto 0) (4 x 24 = 96), and mean_medium is type unsigned.

When I code the following line

signal mean_medium : unsigned (23 downto 0) := (others => '0');
mean_medium <= unsigned(medium (95 downto 75)) +
               unsigned(medium (71 downto 51)) +
               unsigned(medium (47 downto 27)) +
               unsigned(medium (23 downto 3)) ;

I took the following warning:

Width mismatch. mean_medium has a width of 24 bits but assigned expression is 21-bit wide.

Do you have any suggestions to fix this?


Solution

  • An error already is that you divide by four by shifting 3 bits. You only need to shift 2 bits.

    But for correct/precise arithmetic you should not pre-shift the operants of that expression, as you lose precision due to trunctation. First add all the 4 full 24-bit values to one 26-bit output. Then shift-and-round the output. Example

    signal mean_medium : unsigned (23 downto 0); -- redundant := (others => '0');
    signal mean_temp : unsigned(25 downto 0);
    
    mean_temp <=
        resize(unsigned(medium (95 downto 72)), mean_Temp'length) +
        resize(unsigned(medium (71 downto 48)), mean_Temp'length) +
        resize(unsigned(medium (47 downto 24)), mean_Temp'length) +
        resize(unsigned(medium (23 downto 0)), mean_Temp'length) +
        2; -- round factor
    
    mean_medium <= shift_right(mean_temp, 2); --divide by 4
    

    p.s. you could also combine this in one line, removing the necessity of mean_temp.