Hallo Zusammen,
in meinem Design habe ich ein Moving Average Filter, das bisher so
aussieht:
1 | library IEEE;
|
2 | use IEEE.Std_Logic_1164.all;
|
3 | use IEEE.Numeric_std.all;
|
4 | use IEEE.math_real.log2;
|
5 | use IEEE.math_real.ceil;
|
6 |
|
7 |
|
8 | entity moving_average is
|
9 | generic (
|
10 | c_width : integer := 14; -- Bit width of input values
|
11 | c_average_depth : integer := 4 -- Amount of averaging
|
12 | );
|
13 | port (
|
14 | CLK : in std_logic;
|
15 | RESET : in std_logic;
|
16 | DATA_IN : in std_logic_vector(c_width - 1 downto 0); -- Data input
|
17 | VALID_IN : in std_logic; -- Data valid input
|
18 | DATA_OUT : out std_logic_vector(c_width - 1 downto 0); -- Data output
|
19 | DATA_OUT_LONG : out std_logic_vector(c_width + (integer(ceil(log2(real(c_average_depth))))) - 1 downto 0) -- Data output (not rounded to input with)
|
20 | );
|
21 | end moving_average;
|
22 |
|
23 |
|
24 | architecture rtl of moving_average is
|
25 |
|
26 | constant c_count_width : integer := integer(ceil(log2(real(c_average_depth))));
|
27 | type taverage_array is array (c_average_depth - 1 downto 0) of unsigned(c_width - 1 downto 0);
|
28 | signal s_average_array : taverage_array := (others => (others => '0'));
|
29 | signal s_add_reg : unsigned(c_width + c_count_width - 1 downto 0) := (others => '0');
|
30 |
|
31 | begin
|
32 |
|
33 | pfifo : process (CLK) is
|
34 | variable i : integer range 0 to c_average_depth - 1 := 0;
|
35 | begin
|
36 | if rising_edge (CLK) then
|
37 | if RESET = '1' then
|
38 | s_average_array <= (others => (others => '0'));
|
39 | else
|
40 | if VALID_IN = '1' then
|
41 | s_average_array(0) <= unsigned(DATA_IN);
|
42 | for i in 0 to c_average_depth - 2 loop
|
43 | s_average_array(i+1) <= s_average_array(i);
|
44 | end loop;
|
45 | end if;
|
46 | end if;
|
47 | end if;
|
48 | end process pfifo;
|
49 |
|
50 | padd : process (s_average_array)
|
51 | variable v_add_reg_temp : unsigned(c_width + c_count_width - 1 downto 0) := (others => '0');
|
52 | begin
|
53 | v_add_reg_temp := (others => '0');
|
54 | for i in 0 to c_average_depth - 1 loop
|
55 | v_add_reg_temp := v_add_reg_temp + s_average_array(i);
|
56 | end loop;
|
57 | s_add_reg <= v_add_reg_temp;
|
58 | end process padd;
|
59 |
|
60 | DATA_OUT <= std_logic_vector(s_add_reg(c_width + c_count_width - 1 downto c_count_width));
|
61 | DATA_OUT_LONG <= std_logic_vector(s_add_reg);
|
62 |
|
63 | end rtl;
|
Wird hier z.B. der gleitende Mittelwert über 4-8 Werte gebildet,
funktioniert die Sache super. Nun muss ich aber über 64 Werte mitteln.
Da aus einem anderen Porzess getaktet auf "DATA_OUT" zugegriffen wird,
ist das Design viel zu langsam - etwa 13MHz auf einem Spartan 3e (es
müsste mindestens 25 schaffen). Eine Möglichkeit wäre, nicht den jeweils
ersten Wert von der Summe abzuziehen, sondern den Mittelwert. Gibt es
einen Weg das Design schneller zu machen, ohne auf diesen Trick zurück
zu greifen?
Danke und viele Grüße
Achim