Wie addiere ich die einfallenden bits einer seriell gesampelten
Schnittstelle so, dass ich die Summe der Bits bekomme, die 1 sind? Die
bits, die einfallen, werden in einen seriellen Vektor input (15 downto
0) geschoben. Ich möchte einen Mehrheitsentscheid machen bei 12 und 4,
um eine Hysterese zu bekommen und habe folgendes hingeschrieben:
- der leere Vektor ist der Platzhalter für die Länge
- das "downto" habe ich einsetzen müssen, weil er ein einzelnes Bit
nicht nimmt.
Obwohl es Phasen gibt, in denen bis zu 16 bits High sind, zählt die
Summe nur bis 8 hoch. Es scheint einen versteckten ÜBerlauf zu geben,
den ich mir nicht erklären kann, weil der empty_vector 6 downto 0 ist,
also genug Platz hat. als der noch nicht drin war, addierte der
Konstrukt nur bis maximal 3.
Ich bin mir bewusst, dass das kein sauberes VHDL ist, orientiere mich
aber diesbezüglich an vorhandenem Code des Vorgängers.
Da es aber nicht funktionert, die Frage:
*****************************************************
Wie formuliert man dies am Schlauesten (und richtig)?
*****************************************************
Eine Flankenerkennung mit signed, bei denen die einen Bits abgezogen
werden, funktioniert genau so (wenig): Es entstehen positive und
negative Maxima, die die Flanken markieren, aber auch dort entsteht nur
die halbe der maximalen Amplitude. Bei einer perfekten Flanke müsste
aber 0*8 -1*8 = -8 rauskommen. Angezeigt werden aber maximal -4 und +4.
Ich habe auch probiert, vor den unsigned noch eine Null voranzustellen,
also:
+ unsigned ('0' & input(15 downto 15)) und
+ unsigned ("0000" & input(14 downto 14))
aber ohne Verbesserung.
Simuliert wurde mit Vivado-SIM.
Kannst du mal den kompletten Code posten in dem man auch die Signal
Deklaration sieht? Gerne auch als minimales Beispiel falls der Code
etwas groesser ist.
Generell wuerde ich das Ganze mit einer for-Loop und einer if Abfrage
loesen. Viel einfacher und besser lesbar, die Hauptarbeit nimmt dir eh
das Synthese Werkzeug ab. Hier ein bisschen Inspiration:
https://vhdlguru.blogspot.com/2017/10/count-number-of-1s-in-binary-number.html
Ich wuerde direkt Variante 1 bevorzugen, sofern es Ressourcen und
Geschwindigkeit erlauben.
Generell summiert man die Bits einer seriellen Schnittstelle am Besten
dann auf, wenn man jedes einzelne empfängt. Nicht erst danach, wenn alle
empfangen sind.
Wenn das Kind aber schon im Brunnen liegt, dann sieh dir das an:
http://www.lothar-miller.de/s9y/archives/86-Einsen-im-Vektor-zaehlen.html
Tobias B. schrieb:> Kannst du mal den kompletten Code posten in dem man auch die> Signal Deklaration sieht?
Das ist zuviel Zeug zum posten, daher habe ich es ja herauskopiert. Die
Signale sind alles std_logic.
Tobias B. schrieb:> Generell wuerde ich das Ganze mit einer for-Loop und einer if Abfrage> loesen.
Wie soll das gehen? Die Loop wird doch nur während der Synthese
ausgeführt. Es müsste sich auch explizit hinschreiben lassen. Ausserdem
müsste ich ja ERST wissen wie es aussieht, um es dann in den Loop packen
zu können. Das spart ja nur Beschreibung.
Lothar M. schrieb:> Generell summiert man die Bits einer seriellen Schnittstelle am Besten> dann auf
Das geht nicht weil durch die Summation ein FIR-Filter realisiert ist,
dass mit jedem Bit neu ausgeführt wird. Also FIR (Bit 1 ... Bit 16),
dann FIR (Bit 2 ... Bit 17), also müssen alle gespeichert werden.
Es muss doch möglich sein, eine VHDL Zeile zu schreiben, die 16 Werte
summiert! Wenn ich normale Vektoren mit mehr, als einem Bit habe, kann
ich das ja auch so schreiben. Es sind halt nur diesmal Vektoren mit der
Länge 1.
-------------------------
Auf der Seite Lothars ersehe ich aber das Problem:
Man muss die Bits vor der Addition auf die komplette mögliche Breite
des Ergebnissen aufziehen, um sie zu additionsfähigen Vektoren zu
machen. Offenbar verschluckt er sonst Stellen. Der dort abgebildete Code
sieht nämlich so aus:
1
process(i)
2
variablecnt:unsigned(4downto0);
3
begin
4
cnt:="00000";
5
forcin0to15loop
6
cnt:=cnt+unsigned'("0000"&i(c));
7
endloop;
8
o<=std_logic_vector(cnt);
9
endprocess;
Das werde ich ausprobieren!
Allerdings ist ja auch das ein "Rechnen mit Vektoren", was eigentlich
vermieden werden soll. Meines Wissens geht das besser mit Integers /
Naturals und im Bezug auf das Skalieren mit 'resize'. Allerdings habe
ich es trotz Studium der Syntax damit nicht hinbekommen.
Wenn da noch jemand eine Idee hat ... gerne.
Herbert schrieb:> Das geht nicht weil durch die Summation ein FIR-Filter realisiert ist,> dass mit jedem Bit neu ausgeführt wird. Also FIR (Bit 1 ... Bit 16),> dann FIR (Bit 2 ... Bit 17), also müssen alle gespeichert werden.>> Es muss doch möglich sein, eine VHDL Zeile zu schreiben, die 16 Werte> summiert!
Du bekommst die Bits seriell rein? Z. B. von einem Mikrophon das die als
PDM ausgibt? Du willst die dann tiefpassfiltern mit einem einfachen
gleitenden Mittelwert über z. B. 16 Bits?
Dann nehme ein Schieberegister der Länge 16 und eine Summe mit 4 Bits.
Schiebe in jedem Takt.
Addiere in jedem Takt das neu ankommende Bit und subtrahiere das letzte
Bit aus dem Schieberegister.
Du könntest deinen 1 Bit Eingang aber auch einfach als std_logic_vector
deklarieren.
BIT_NEU : in std_logic_vector(0 downto 0);
Dann kannst du das intern direkt als unsigned interpretieren lassen:
... + unsigned(BIT_NEU);
Alternativ kannst du das Bit auch als std_logic lassen und quasi für
eine Entscheidung verwenden:
if BIT_NEU = '1' then
summe <= summe +1;
end if;
Herbert schrieb:> Es muss doch möglich sein, eine VHDL Zeile zu schreiben, die 16 Werte> summiert!
Warum "muss" es das? Warum meinst du, dass 1 einzige Zeile effizienter
umgesetzt wird als 10 Zeilen?
Schreib halt eine Funktion countones() und füttere die mit dem Vektor.
Dann steht da summe <= countones(input);
> Allerdings ist ja auch das ein "Rechnen mit Vektoren", was eigentlich> vermieden werden soll.
Juckt doch nicht. Der Overhead wird sowieso wegoptimert.
> Das geht nicht weil durch die Summation ein FIR-Filter realisiert ist,> dass mit jedem Bit neu ausgeführt wird.> Also FIR (Bit 1 ... Bit 16), dann FIR (Bit 2 ... Bit 17)
Bei dieser Rechnung muss ich doch nur das erste und das letzte Bit
bearbeiten (z.B. einen "Einser-Zähler" inkrementieren bzw.
dekrementieren), die in der Mitte bleiben ja gleich und ändern die Summe
nicht.
> also müssen alle gespeichert werden.
Sehe ich zwar anders, aber du hast das Modul in ganzer Pracht vor dir
und hast das sicher untersucht.
Lothar M. schrieb:> ei dieser Rechnung muss ich doch nur das erste und das letzte Bit> bearbeiten (z.B. einen "Einser-Zähler" inkrementieren bzw.> dekrementieren), die in der Mitte bleiben ja gleich und ändern die Summe> nicht.
Es steckt aber noch ein spike Filter drin, eine Reinterpreation der
doppelten Bits aufgrund eines zu hohen Sampletaktes und mehr. Man kann
es NICHT einfach nur durch zählen machen, sonst täte ich das ja. Die
Schaltung die das zuvor erledigte, war sogar ein CIC.
Genau deshalb geht auch gustels Vorschlag nicht. Ich habe es nun drin
und es geht. Danke.
Herbert schrieb:> Tobias B. schrieb:>> Generell wuerde ich das Ganze mit einer for-Loop und einer if Abfrage>> loesen.> Wie soll das gehen? Die Loop wird doch nur während der Synthese> ausgeführt.
Das ist synthesefähig solange die Teile innerhalb der Loop nicht
Ergebnisse der vorhergehenden Iteration benötigen (Unabhängig sind). Der
Synthesizer macht einfach eine loop-unroll.
> Das spart ja nur Beschreibung.
Richtig erkannt.
Lothar M. schrieb:>> Das geht nicht weil durch die Summation ein FIR-Filter realisiert ist,>> dass mit jedem Bit neu ausgeführt wird.>> Also FIR (Bit 1 ... Bit 16), dann FIR (Bit 2 ... Bit 17)> Bei dieser Rechnung muss ich doch nur das erste und das letzte Bit> bearbeiten (z.B. einen "Einser-Zähler" inkrementieren bzw.> dekrementieren), die in der Mitte bleiben ja gleich und ändern die Summe> nicht.
Damit würden aber Werte am Rand genau so bewertet wie jene in der Mitte
der Schlange. Bei einem echten FIR ist das nicht der Fall. Hier offenbar
schon, da gleitender Mittelwert, wenn ich das richtig interpretiere.
Gleichwohl muss man sich alle Werte der Vergangenheit speichern, um
jeweils zu wissen, welcher abzuziehen ist.
Wenn es dann kein bewertender Filter ist, wäre natürlich auch so lösbar,
wie beim CIC, indem nur Summiert und abgetastet wird. Durch die
Differenzbildung der jeweils letzten Samples wird die komplette Historie
mit eliminiert.
Die eigentliche Frage des TE würde ich so lösen, dass die Bits in einen
Vektor verwandelt werden und vor der Rechnung mit resize angepasst
werden. Das ist der formell korrekte Weg. Führt aber zu keinem anderen
Ergebnis :-)
Jürgen S. schrieb:> Damit würden aber Werte am Rand genau so bewertet wie jene in der Mitte> der Schlange. Bei einem echten FIR ist das nicht der Fall. Hier offenbar> schon, da gleitender Mittelwert, wenn ich das richtig interpretiere.
Doch, das ist ein echter FIR. Nur haben eben alle Koeffizienten den
gleichen Wert. Das Verhalten ist also eher schlecht, aber man spart sich
Multiplikationen.
Statt nur 1sen zu summieren könnte man ja auch aus jeder 1 einen Wert
mit z. B. 8 Bits machen, also alle Bits mit 1 füllen. Und dann könnte
man auch einen besseren FIR mit Multiplikationen rechnen. Ist wohl eine
Abwägung.
Gustl B. schrieb:> Doch, das ist ein echter FIR. Nur haben eben alle Koeffizienten den> gleichen Wert.
Formell ja, aber ich hatte natürlich einen FIR mit individuellen Koeffs
im Sinn.