Forum: FPGA, VHDL & Co. sin² hinter ADC


von Michael (Gast)


Lesenswert?

Hallo zusammen,

ich habe einen 8bit ADC, der ein Sinussignal digitalisiert.

Nun möchte ich dieses Sinussignal digital quadrieren.

Ich habe also angefangen und habe einen sequentiellen Multiplizierer 
gebaut und als ich fertig war ist mir etwas aufgefallen, woran ich nun 
etwas verzweifle.

Der ADC gibt Werte von 0 bis 256 aus. Dabei fallen 128 Werte auf die 
positive Halbwelle und 128 Werte auf die negative Halbwelle.
0 => 127     negative Werte
127 => 255   positive Werte

Nun hatte ich die Idee, einfach das oberste Bit als Vorzeichenbit zu 
interpretieren, dadurch die negative Halbwelle einfach nach oben zu 
kippen und dann die verbleibenden 7 bit zu quadrieren. Aber das geht 
leider nicht, da nach dem Nulldurchgang die nächste Stelle 0111.1111 ist 
und nicht 0000.0001. So war diese Idee hinfällig.

Nun stehe ich etwas auf dem Schlauch und habe keine Idee, wie ich das in 
VHDL umsetzen kann.

Hat jemand dazu eine Idee bzw. kann helfen?

Vielen Dank!
Michael

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Michael schrieb:
> Ich habe also angefangen und habe einen sequentiellen Multiplizierer
> gebaut
Warum selber bauen? In VHDL sieht eine Multiplikation so aus:
y <= a*b;
Und die Quadratur mithin
y <= a*a;

> 0 => 127     negative Werte
> 127 => 255   positive Werte
127 ist also mal positiv und mal negativ?

> Nun hatte ich die Idee, einfach das oberste Bit als Vorzeichenbit zu
> interpretieren
Ich würde einfach signed rechnen (macht ja Sinn mit einem negativen 
Wert), und vorher einen Wert von 127 (müssen das nicht 128 sein?) vom 
ADC-Wert abziehen...

von Georg A. (georga)


Lesenswert?

> Nun möchte ich dieses Sinussignal digital quadrieren.

Wenn es nicht mehr als 8-10 Bit werden, passt der ganze Kram doch bequem 
in eine Lookup-Table rein. Bei Xilinx-FPGAs zB. in ein BRAM. Braucht 
keine Logik und ist auch noch schneller (fertig) als so ein 
Multiplizierer ohne dedizierte Logik (DSP/MUL-Blöcke).

von Michael (Gast)


Lesenswert?

Hallo,

Lothar Miller schrieb:
> 127 ist also mal positiv und mal negativ?
Das war ein Fehler meinerseits, die 128 der erste positive Wert.

Georg A. schrieb:
> Wenn es nicht mehr als 8-10 Bit werden
Die Sache könnte später auch auf 10 oder gar 12bit ausgebaut werden. 
Eine LUT ist also weniger ratsam.

Lothar Miller schrieb:
> Warum selber bauen? In VHDL sieht eine Multiplikation so aus:
Ich habe einen generic eingefügt, der mir erlaubt anzugeben, wieviele 
Additionen pro Takt ausgeführt werden. Damit steigt zwar der 
Platzbedarf, aber ich bin später nicht darauf angewiesen, dass die 
Multiplikation immer so viele Takte wie Bits benötigt und ich kann bei 
freien Ressourcen auch alles mit einem Takt abhandeln.

Lothar Miller schrieb:
> Ich würde einfach signed rechnen
Ich habe mich bisher immer erfolgreich gedrückt, wenn es um das Rechnen 
mit signed ging. Das Vorzeichenbit hat mich immer verwirrt, aber 
vielleicht ist es auch nur halb so wild. Aber nun werde ich wohl nicht 
drum herum kommen.

Also konvertiere ich die ADC-Werte durch Subtraktion mit 128 in 
signed... ok, muss ich mich belesen, wie das genau funktioniert und 
korrekt ist.
Wie würdest Du das berechnen?
1
adc_wert_sgn(8 downto 0) <= unsigned(adc_wert);
2
adc_wert_scale <= adc_wert_sgn - 128;

oder mache ich einfach eine signed-Extension vom adc_wert und 
subtrahiere dann 128?
1
adc_wert_sgn(8 downto 0) <= sxt(adc_wert);
2
3
adc_wert_sgn(8 downto 0) <= adc_wert(adc_wert'HIGH) & adc_wert;

Vielen Dank!
Michael

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Angehängte Dateien:

Lesenswert?

Michael schrieb:
> dass die Multiplikation immer so viele Takte wie Bits benötigt
In einem halbwegs aktuellen FPGA braucht die komplette Multiplikation 
genau 1 Takt, denn da gibt es ja jede Menge Multiplizierer....

Michael schrieb:
> Also konvertiere ich die ADC-Werte durch Subtraktion mit 128 in
> signed... ok, muss ich mich belesen, wie das genau funktioniert und
> korrekt ist.
> Wie würdest Du das berechnen?
So ginge das:
1
    port (...
2
          x : in  std_logic_vector(7 downto 0);
3
          y : out std_logic_vector(7 downto 0);
4
          ...
5
          );
6
7
:
8
9
signal u : unsigned (7 downto 0);
10
signal s : signed (7 downto 0);
11
12
:
13
14
  u <= unsigned(x);
15
  s <= signed(u-to_unsigned(128,8));
16
  y <= std_logic_vector(s);
Aber (hmhm... räusper...) das Invertieren des MSB macht das selbe... 
;-)
(siehe die unteren beiden Zeilen im Screenshot der Simulation)

von Michael (Gast)


Lesenswert?

Vielen Dank!

Nun habe ich zwei signed-Werte und muss diese mit meinem Multiplizierer 
vereinen, der auf std_logic_vector ausgelegt ist.
Ich habe schon gewusst, wieso ich bisher immer behaarlich 
signed-Berechnungen umgangen habe. :-)

Aber nun komme ich wohl nicht umhin, es mal damit zu versuchen.

Oder komme ich mit dem not(MSB) doch wieder drum herum, weil ich bei 
std_logic_vector bleiben kann. Ich finde diesen signed-Datentyp immer 
noch höchst umständlich, weil man nie sicher sein kann, wie dieser Wert 
nun interpretiert werden kann.

Kann ich denn signed einfach so quadrieren und bekomme dann auch ein 
richtiges Ergebnis?

Ich muss mich mit signed noch vertraut machen, ob es wirklich nur ein 
std_logic_vector mit einem MSB mehr ist, was das Vorzeichen vorgibt.

Vielen Dank!
Micha

von Christian R. (supachris)


Lesenswert?

Michael schrieb:
> std_logic_vector bleiben kann. Ich finde diesen signed-Datentyp immer
> noch höchst umständlich, weil man nie sicher sein kann, wie dieser Wert
> nun interpretiert werden kann.

Genau anders herum ist es doch. Ein Vektor kann alles darstellen und der 
Nutzer muss sich um die Interpretation kümmern.

> Kann ich denn signed einfach so quadrieren und bekomme dann auch ein
> richtiges Ergebnis?

Na klar. Einfach Signed * Signed. Das Ergebnis ist dann zunächst mal 
doppelt so breit und kann wieder nach std_logic_vector zurück gecastet 
werden. Was ist daran kompliziert? Das sinnlose höchste Bit nach der 
Quadrierung kannst du ja dann mit resize wieder wegmachen. Ich weiß 
nicht, ob der Synthesizer erkennt, ob das Ergebnis ein Bit weniger 
braucht. Bei einer normalen Mul sagt er dir sogar (im Gegensatz zur 
Addition) wenn die Bitbreiten nicht stimmen.

Das Offset sollte so am einfachsten klappen:

adc_wert_scale <= signed(unsigned(adc_wert) - to_unsigned(128, 8));

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.