Forum: FPGA, VHDL & Co. Mittelwertbildung aus 16 16-Bit-Worten


von Andi (Gast)


Lesenswert?

Hallo zusammen,

ich möchte in VHDL (Xilinx) aus 20 8-Bit-Worten den arithmetischen
Mittelwert bilden, hab aber keine Idee wie ich ansetzen soll.
Die 16-Bit-Worte werden seriell über I2C eingelesen und sollen dann zur
Mittelwertbildung dienen.

Dazu brauche ich wohl ein Shift-Register als Eingangspuffer, oder?


Vielleicht kann mir da ja jmd. weiterhelfen.
Wäre für jede Antwort dankbar.


Danke im Voraus

Gruß
Andi

von Andi (Gast)


Lesenswert?

Sorry
Hab 2 Fehler in meinem ersten Beitrag:

Möchte 16 6-Bit-Worte mitteln!


Gruß
Andi

von Hagen (Gast)


Lesenswert?

Du hast ein 10Bit Register auf das deine 16 6Bit Werte addiert werden,
in den obersten 6 Bits steht dann der Mittelwert.

Ob due diese Addition nun live bei jedem Empfang eines 6Bit Wertes
machst oder erst im nachhinhein mit alle 16 Werte gleichzeitig hängt
von dir ab.

Gruß hagen

von Andi (Gast)


Lesenswert?

Hallo Hagen,

zuerst mal DANKE für deine Antwort.

Kann ich die 6-Bit-Worte einfach addieren?
z.B.:  Summe <= Daten(15) + Daten(14) + Daten (13) + ... + Daten(0);
(wobei  Daten(xx) je ein 6-Bit-Wort ist)


Gruß
Andi

von nides (Gast)


Lesenswert?

Warum solltest du das nicht können?
Es kommen halt immer wieder Bits hinzu.
nach 1 Add. sind es 7 Bit, nach 4 Add. 8 Bit usw...

Überleg es dir einfach mal auf dem Papier durch.
Schafft oft Klarheit!

Nides

von Hagen (Gast)


Lesenswert?

Summe <= Summe + "0000" & Daten; falls du sequientiell sofort nach
Empfang der Daten diese addierst. Dies sollte Resourcen sparen.

Die Anzahl der nötigen MSBits für Summe ist abhängig von der Anzahl der
Daten Elemente die du darauf addieren möchtest. Anzahl Stellen zur basis
2 = Ln2(Anzahl Datenelemente).

Bei  2 Datenelementen also 1 Bit mehr = 2^1
Bei  4 Datenelementen also 2 Bit mehr = 2^2
Bei  8 Datenelementen also 3 Bit mehr = 2^3
Bei 16 Datenelementen also 4 Bit mehr = 2^4

merkst du was ?

Bei der Addition zweier 6 Bit Werte entsteht 1 Bit Überlauf, also
entsteht bei 2* 2 Addtionen = 4 somit 2 Bits Überlauf, bei 2*2*2 =
Additionen also 3 Bits usw.usw.

Der normale arithmetische Durschnitt berechnet sich aus Summe(Elemente)
/ Anzahl Elemente. Da du clevererweise 16 Elemente hast vereinfacht dies
die Division, auf einen binären Rechtsshift um 4 Bits = / 2^4 = / 16. Da
aber in VHDL mit Bit Vekroten gerechnet wird reicht es also aus einfach
Result(5 downto 0) := Summe(Elemente)(10 downto 4) zu benutzen.


Gruß Hagen

von Hagen (Gast)


Lesenswert?

Ob du nun alle 16 Werte einfach addieren und danach durch 16 teilen
musst hängt von deiner Mittelwert Formel ab. Ich ging vom normalen
arithmetischen Mittel, populär auch als Durchschnitt bekannt, aus.

Es gibt aber auch andere Mittelwert Formel.

Gruß Hagen

von Andi (Gast)


Lesenswert?

Danke nides und Hagen,

war beruflich unterwegs, desshalb die späte Antwort. Habt vielen Dank
für die Antworten. Mir ist jetzt einiges klarer. Ich hoffe ich komme
jetzt zurecht.


Beste Grüße

Andi

von 123 (Gast)


Lesenswert?

ist die genauigkeit gleich wenn ich erst durch 16 teil und dann addiere?

von Hagen (Gast)


Lesenswert?

Nein ist sie nicht. Wenn du zuerst 16 6 Bit Werte addierst so benötigst
du einen 10 Bit Summenwert. Du hast also 6 Bit Vorkomma und 4 Bit
Nachkommastellen als Genauigkeit. Dividierst du aber die 6 Bit Werte
vorher schon durch 16 so verlierst du 4 Bit an Genauigkeit in den
Vorkommastellen. Es wird also im Worstcase 8 Bit ungenauer als mit der
ersteren Methode.

Du könntest aber die Summe als 7 Bit Wert speichern. Deine 6 Bit Werte
werden durch 8 dividiert, also 3 Bits werden entfernt. Vorher musst du
aber diese Werte runden, sozusagen auf +- 0.5 Vorkommastellen. Am Ende
der 16 Additionen hast du in Summe alle addierten Werte und musst diese
noch durch 2 teilen. Das Resultat sollte sich dann nicht von der ersten
Methode unterscheiden, falls du bei der das Resultat ebenfalls
rundest.

Gruß Hagen

von Andi (Gast)


Lesenswert?

Hallo Leute,

ich hab mich jetzt mit euren Tipps an die Arbeit gemacht und es ist
folgendes dabei herausgekommen.

entity Mittelwert is
    Port ( clk    : in  std_logic;
           reset  : in  std_logic;
           enable : in  std_logic;
           data    : in  std_logic_vector(5 downto 0);
           done : out std_logic;
           Mittelwert : out std_logic_vector(5 downto 0)
      );
end Mittelwert;


architecture Behavioral of Mittelwert is

   type InputBuffer is array (15 downto 0) of
                              std_logic_vector(5 downto 0);

   signal Summe : std_logic_vector(9 downto 0);

begin

   process (clk, Reset, enable, data)
   begin
      if (Reset = '1') then
         done <= '0';
         Summe <= (others => '0');
      elsif (rising_edge(clk)) then
         done <= '0';
         if (enable = '1') then
            Summe <= (Summe + ("0000" & data));
            DoneFlag <= '1';
         end if;
      end if;
   end process;

   Mittelwert <= Summe(9 downto 4);

end Behavioral;

Leider funktioniert dieses Design nicht. Ich habe versucht es als
'component' in ein anderes File einzubinden.

Vielleicht findet Ihr ja den Fehler.


Gruß
Andi

von FPGA-User (Gast)


Lesenswert?

@Andi

Du bist lustig, hättest ja wenigstens mal schreiben können, was
nicht funktioniert.
Hast Du das Design mal simuliert? Auf jeden Fall fehlt oben die
Signal-Deklaration für DoneFlag. Dafür hättest Du aber sicher
sowohl bei Simulation als auch bei der Synthese eine passende
Fehlermeldung bekommen.
Ich schau mal weiter...

von FPGA-User (Gast)


Lesenswert?

@Andi

was soll denn mit dem InputBuffer werden (derzeit nicht benutzt)?!
Kommen die 6 bit Werte sequentiell mit jedem Takt oder
nur wenn enable aktiv ist oder .... ?
Bitte mehr Infos, wenn Dir geholfen werden soll.

von J. S. (engineer) Benutzerseite


Lesenswert?

Wollte ich auch gerade sagen! Ich gehe davon aus, daß die Daten
sequentiell kommen, sonst würde die MW-bildung auch keinen Sinn machen.

von Andi (Gast)


Lesenswert?

Hallo Leute,

ich hab's erneut versucht und dabei kam folgendes heraus:

entity MW is
   port ( clk : in std_logic;
          reset : in std_logic;
          enable : in std_logic;
          InData : in std_logic_vector(5 downto 0);
          done : out std_logic;
          mw : out std_logic_vector(5 downto 0)
         );
end MW;

architecture Bahavioral of Average is

   type Puffer is array (15 downto 0) of
                         std_logic_vector(5 downto 0);

   signal Summe : std_logic_vector(9 downto 0);
   signal InBuffer : Puffer;
   signal shifted : std_logic;
   signal int_done : std_logic;

begin

   process (clk, reset, enable, InData)
   begin
      if (reset = '1') then
         InBuffer <= (others => "000000");
         shifted <= '0';
      elsif (rising_edge(clk)) then
         if (enable = '1') then
            InBuffer <= (InBuffer(14 downto 0) & InData);
            shifted <= '1';
         else
            shifted <= '0';
         end if;
      end if;
   end process;

   process (clk, reset, shifted, InBuffer)
   begin
      if (reset = '1') then
         Summe <= (others => '0');
      elsif (rising_edge(clk)) then
         if (shifted = '1') then
            Summe <= ("0000" & InBuffer(15)) +
                     ("0000" & InBuffer(14)) +
                      ...
                     ("0000" & InBuffer(0));
            int_done <= '1';
         elsif (shifted = '0') then
            int_done <= '0';
         end if;
      end if;
   end process;

   mw <= Summe(9 downto 4);
   done <= int_Done;

end Behavioral;


Ich kann die seriell ankommenden Daten nicht sofort addieren, da ich
einen kontinuierlichen MW haben will. D. h. es soll erst der Puffer als
Shift-Reg. fungieren in den ein ständiger Datenstrom fließt. Immer wenn
ein 6-Bit-Wort eingelesen wird, fällt oben aus dem Puffer wieder ein
Wert raus. Der MW soll aus den 16 Pufferwerten ermittelt werden.

Ich kann euch leider nicht sagen was nicht funktioniert, ich weiß nur,
dass ich keinen MW zurückbekomme.

Ich hab einen seriellen Datenstrom vom I2C-Bus, möchte diese Daten dann
mitteln (Rauschminimierung) und anschließend wieder über den I2C-Bus
schicken.

Der Mittelwert-Filter soll als component in ein anderes file eingefügt
werden.

Der Ablauf soll wie folgt aussehen: Lesen vom Bus, MW-Bildung,
Schreiben auf den Bus

Hab dazu eine State-Machine realisiert: (Ausschnitt aus dem
Hauptprogramm)

...
signal state, nextstate : std_logic_vector(1 downto 0);
...

process: (clk, reset)
begin
   if (reset = '1') then
      state <= "00";
   elsif (rising_edge(clk)) then
      state <= nextstate;
   end if;
end process;

process (state)
begin
  nextstate <= state;
  case state is
     when "00" =>   -- I2C-Bus Initialisieren
           ...
     when "01" =>   -- lesen vom I2C-Bus
           ...
     when "10" =>   -- MW-Bildung
           enable <= '1';  -- enable-signal für MW
           if (done = '1') then  -- wenn MW berechnet
              enable <= '0';
              berechneterMW <= MW;   -- MW aus dem Modul
                                     -- MW an eines internes
                                     -- Signal des Hauptprogramms
                                     -- zuweisen
              nextstate <= "11";
           end if;
     when "11" =>   -- senden auf I2C-Bus
     when others =>
        nextstate <= "00";
  end case;
end process;


Ich bin nun schon seit einigen Wochen dran und schaffe es einfach
nicht. Es ist zum verzweifeln.

Ich hoffe ihr könnt mir weiterhelfen.

Vielen Dank

Gruß
Andi

von Xenu (Gast)


Lesenswert?

Das Signal "shifted" geht mit der clk-Flanke auf '1', falls enable
'1' ist. Bei der nächsten Flanke geht "int_done" auf '1'.

Willst Du das so?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.