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
Sorry Hab 2 Fehler in meinem ersten Beitrag: Möchte 16 6-Bit-Worte mitteln! Gruß Andi
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
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
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
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
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
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
ist die genauigkeit gleich wenn ich erst durch 16 teil und dann addiere?
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
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
@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...
@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.
Wollte ich auch gerade sagen! Ich gehe davon aus, daß die Daten sequentiell kommen, sonst würde die MW-bildung auch keinen Sinn machen.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.