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
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
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.
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