Forum: FPGA, VHDL & Co. Integer aufspalten


von Stephan J. (meskalin)


Lesenswert?

Ahoy Hoy.

Ich habe einen Integer und möchte davon aber nur einen bestimmten 
Bereich nutzen. Und überlege ob ich einen nützlichen Befehl übersehen 
habe.

Mein Integer ist sechsstellig und mich interessieren eigentlich nur die 
höheren drei Stellen.
Faktisch kommt es einer Division mit 1000 gleich, wobei ich den 
Nachkommabereich weglasse. Aber wenn ich nach Division suche, dann 
kommen immer große Quellcodes die richtige Division können. Brauch ich 
ja eigentlich nicht, und halte das auch etwas mit Kanonen auf Spatzen 
geschossen.

Gibt es eine Möglichkeit die da einfacher ist? Wenns ein Vektor wäre, 
wärs ja ziemlich einfach. Habe auch schon überlegt den Integer in einen 
Bitvektor zu wandeln. Dann wären zwar Teilung durch zwei absolut 
einfach, aber 10 is dann auch nicht so einfach zu realisieren.

Für Tipps Dankbar

von Udo S. (urschmitt)


Lesenswert?

10 Shift left wären eine Division durch 1024.

von Paul (Gast)


Lesenswert?

Wenn ich dein Problem richtig verstanden habe, kannst du doch den Shift 
Operator verwenden,oder nicht?

von Udo S. (urschmitt)


Lesenswert?

Udo Schmitt schrieb:
> 10 Shift left wären eine Division durch 1024.

Blödinn, natürlich rechtsshiften , nicht nach links! Sorry für den 
Fehler.

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


Lesenswert?

Stephan J. schrieb:
> Wenns ein Vektor wäre, wärs ja ziemlich einfach.
Was meinst du, wie ein Integer in der Hardware aussieht?
Richtig: das ist ein Vektor.

Also müsstest du, falls du VHDL machst, den nur ein wenig konvertieren 
und casten, und könntest dann die unteren 10 Bits abschneiden für eine 
Division durch 1024. Wobei das genau genommen nur für unsigned Werte 
gilt...
http://www.lothar-miller.de/s9y/archives/14-Numeric_Std.html

von P. K. (pek)


Lesenswert?

Generell gesagt: Eine Division durch eine Konstante läuft immer auf eine 
Multiplikation mit einem Ganzzahlwert und teilen durch 2^^N hinaus. Je 
nach Genauigkeit, die Du haben willst, kannst Du mehr oder weniger 
Aufwand betreiben.
X : 1000 kannst Du ereichen mit:

*   1, dann /2^^10, Fehler:  2.34% (die von Udo etc. erwähnte Variante)
* 131, dann /2^^17, Fehler:  0.05%
*2097, dann /2^^21, Fehele: <0.01%

von voodoofrei (Gast)


Lesenswert?

In dem Zusammenhang auch immer ganz nützlich:

http://www.synthworks.com/papers/vhdl_math_tricks_mapld_2003.pdf

von Stephan J. (meskalin)


Lesenswert?

Lothar Miller schrieb:
>> Wenns ein Vektor wäre, wärs ja ziemlich einfach.
> Was meinst du, wie ein Integer in der Hardware aussieht?
> Richtig: das ist ein Vektor.

Das ist mir schon klar. Ich hab ja danach auch noch geschrieben:
Habe auch schon überlegt den Integer in einen
Bitvektor zu wandeln. Dann wären zwar Teilung durch zwei absolut
einfach, aber 10 is dann auch nicht so einfach zu realisieren.

---

Aber ich habe dank ein paar guter Tipps folgende Lösung des Problems 
gefunden, und möchte Leuten, die dasselbe Problem haben, die Lösung 
nicht vorenthalten.

Die 1024 Methode ist ein super Ansatz. Problem war jetzt die 
Ungenauigkeit der restlichen 24.
Bei 360° war das gerade ein Drift von etwa 9°
Dies kann man aber durch multiplikation mit einem Korrekturfaktor wieder 
super ausgleichen.

Zur Erläuterung meines Problems und dessen Lösung:
Habe bei 360° 64 Inkremente. Macht eine Auflösung von 5,625° pro 
Inkrement.
Benutze einen Inkremente Zähler, und einen Integer Wert von 0..359999, 
der sich als Produkt von Inkrementalzähler und 5625 zusammensetzt.
Wenn ich jetzt durch 1024 teilen würde(Shift 10) würde ich einen Drift 
erzeugen, der bei 359999 bereits 9° betrifft.
Nun brauchen wir nur die Gradgenauigkeit anzupassen.
5,625° * 1,024 ergibt die neue Gradeinteilung von 5,760° pro Inkrement.
Den Wertebereich von meinem Integer muss man noch anpassen von 0..359 
*1024.
Funktioniert einwandfrei.

Danke für die Ideen

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


Lesenswert?

Stephan J. schrieb:
> Das ist mir schon klar. Ich hab ja danach auch noch geschrieben:
> Habe auch schon überlegt den Integer in einen
> Bitvektor zu wandeln. Dann wären zwar Teilung durch zwei absolut
> einfach, aber 10 is dann auch nicht so einfach zu realisieren.
Richtig, und deshalb ist es am einfachsten, den Vektor erst mal mit 
irgendwas mutliplizieren, und dann durch eine Zweierpotenz zu teilen.


Peter K. schrieb:
> Generell gesagt: Eine Division durch eine Konstante läuft immer auf eine
> Multiplikation mit einem Ganzzahlwert und teilen durch 2^^N hinaus. Je
> nach Genauigkeit, die Du haben willst, kannst Du mehr oder weniger
> Aufwand betreiben.
> X : 1000 kannst Du ereichen mit ...
Hier mal eine ausführliche Betrachtung des mittleren Falls:
Eine Division wie
ist mathematisch das selbe wie

Und geschickterweise wählt man F jetzt so, dass der Wert
nahe an einer Ganzzahl ist. Mit
wird das erreicht:
Damit ist der Fehler nach Abschneiden der Nachkommastellen kleiner als 
1/1000. In der VHDL-Praxis sieht die Berechnung also so aus:
1
   ergebnis = wert*131 / 1024;
Wobei hier die Berechnung mit integer wegen der eingeschränkten 
Bitbreite evtl. besser durch eine Rechnung mit einem signed oder 
unsigned Vektor ersetzt wird.

Und wenn du sowieso eine ganz andere Skalierung (offenbar in °) willst, 
dann rechne die Faktoren doch gleich so um, dass nach der Rechnung das 
Ergebnis gleich in zehntel oder hundertstel Grad herauskommt...

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.