www.mikrocontroller.net

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


Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry
Hab 2 Fehler in meinem ersten Beitrag:

Möchte 16 6-Bit-Worte mitteln!


Gruß
Andi

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: nides (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: 123 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ist die genauigkeit gleich wenn ich erst durch 16 teil und dann addiere?

Autor: Hagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: FPGA-User (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen Schuhmacher (engineer) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Andi (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Xenu (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.