Zahlenbereich bei Addition

OP #3278914
Hallo

Ich versuche ein Mittelwertfilter zu implementieren und bin mir dabei 
nicht im Klaren, wie gross ich meine Signale machen muss.

Das Eingangssignal kommt von einem ADC und hat eine Breite von 14 Bit. 
Dieses wird danach in einen Integer gewandelt, welcher im Bereich 
-20'000...20000 angelegt ist. "AdcInBufxDS" hat also den Bereich 
-20'000...20000.

Wie kann ich dafür sorgen, dass es keinen Überlauf währen der Addition 
gibt?

Ich könnte natürlich den Bereich des AdcInBufxDS auf +-200000 setzen, 
doch dies scheint mir unschön.

Die Division "/8" ist im Moment eine genügend gute Näherung an "/10" und 
viel einfacher.
1
  FIR_ff : process(ClkxCI, RstxRBI)
2
  begin
3
    if RstxRBI = '0' then
4
      for c in 0 to 9 loop
5
        AdcInBufxDS(c) <= 0;
6
      end loop;
7
    elsif rising_edge(ClkxCI) then
8
      AdcInBufxDS(9) <= AdcInBufxDS(8);
9
      AdcInBufxDS(8) <= AdcInBufxDS(7);
10
      AdcInBufxDS(7) <= AdcInBufxDS(6);
11
      AdcInBufxDS(6) <= AdcInBufxDS(5);
12
      AdcInBufxDS(5) <= AdcInBufxDS(4);
13
      AdcInBufxDS(4) <= AdcInBufxDS(3);
14
      AdcInBufxDS(3) <= AdcInBufxDS(2);
15
      AdcInBufxDS(2) <= AdcInBufxDS(1);
16
      AdcInBufxDS(1) <= AdcInBufxDS(0);
17
      AdcInBufxDS(0) <= to_integer(unsigned(DataInxDI)) - 8192;
18

19
      DataInDecxDO <= NextDataInDecxS;
20
    end if;
21
  end process FIR_ff;
22

23
  FIR_comb : process(AdcInBufxDS)
24
  begin
25
    NextDataInDecxS<= (AdcInBufxDS(9) + AdcInBufxDS(8) + AdcInBufxDS(7) + AdcInBufxDS(6) + AdcInBufxDS(5) + AdcInBufxDS(4) + AdcInBufxDS(3) + AdcInBufxDS(2) + AdcInBufxDS(1) + AdcInBufxDS(0)) /8;
26
  end process FIR_comb;
#3279662
R. K. schrieb:
> Ich könnte natürlich den Bereich des AdcInBufxDS auf +-200000 setzen,
> doch dies scheint mir unschön.

Du wirst nicht darum herumkommen, aber so schlimm ist das in Tat und 
Wahrheit ja nicht. Das bedeutet nichts anderes als Deinen "signed" Wert 
um 3 Bit aufzubohren (19 statt 16 Bit).
OP #3279703
Also verstehe ich die korrekt:

Die Rechnung funktioniert auf der Registergrösse der Operanden und nicht 
des Resultats.
Ich muss die "AdcInBufxDS" mit dem grossen Bereich initialisieren, damit 
die Rechnung korrekt funktioniert. Den "NextDataInDecxS" kann ich jedoch 
auf den kleinen Bereich setzen.
#3279731
So müsste es gehen:
1
    SumxD           <= AdcInBufxDS(9) + AdcInBufxDS(8) + 
2
                       AdcInBufxDS(7) + AdcInBufxDS(6) + 
3
                       AdcInBufxDS(5) + AdcInBufxDS(4) + 
4
                       AdcInBufxDS(3) + AdcInBufxDS(2) + 
5
                       AdcInBufxDS(1) + AdcInBufxDS(0);
6
    NextDataInDecxS <= SumxD(18 downto 3); -- /8

NextDataInDecxS ist dann wieder ein 16-bit-signed.

Simulieren müsste Aufschluss geben.
#3279735
Clemens S. schrieb:
> Moritz A. schrieb:
>> Du kannst schon vor der Addition jeden Wert durch 8 teilen. Dauert zwar
>> ein Moment länger, aber ich glaube nicht dass die Routine hier
>> zeitkritisch ist.
>
> und den rest auch aufsummieren, zum schluss dividieren und dazuzählen,
> dann ist es sogar genau.

Da er achtelt statt zehntelt ist es mit der Genauigkeit hier offenbar 
sowieso nicht so kritisch, daher habe ich den Rest großzügig liegen 
gelassen.
Gast #3279736
ähm... Mittelwert ?

Du addiert 10 Zahlen und dividierst durch 8 ??? hä?

Warum nicht 8 Addieren und durch 8 Dividieren. Dann ist es ein 
Mittelwert.


btw... dieser 10fach addieren wird verdammt langsam. Stichwort 
Pipelining.
btw... Division durch acht ist ein Shift, schreib's auch so hin.

gruß
#3279743
Moritz A. schrieb:
> Da er achtelt statt zehntelt ist es mit der Genauigkeit hier offenbar
> sowieso nicht so kritisch, daher habe ich den Rest großzügig liegen
> gelassen.

Das eine hat mit dem anderen nichts zu tun. Du verlierst nicht mehr an 
Genauigkeit, wenn Du leicht anders skalierst, falls in der 
darauffolgenden Rechnung die absolute Amplitude keine Rolle spielt.
OP #3279767
Genau, die Division "/8" ist lediglich eine Skalierung, da es bei der 
späteren Berechnung nicht wirklich auf die absolute Amplitude ankommt 
ist dies vertretbar. Und die Division durch 8 (Ja ich schreibe Division, 
weil es ja nicht wirklich eins reiner shift ist, wegen des signed) ist 
viel einfacher als eine Division durch 10.

Bezüglich Verarbeitungszeit sehe ich überhaupt kein Problem. Ein 
FIR-Filter (also hier das Moving Average Filter) hat nunmal eine 
Verzögerung der "halben Ordnung" dies kann auch durch ein Piplining 
nicht verbessert werden. Oder sehe ich dies etwa falsch?

Die Ungenauigkeit durch die Division ist vertretbar und macht eine 
spätere Implementation auf einem günstigen ASIC-CPLD einfacher.
#3279840
R. K. schrieb:
> Oder sehe ich dies etwa falsch?

Der Pipelining-Aufwand kommt dann noch oben drauf. Eine "billigere" 
Lösung wäre die Summe zu speichern und jeweils den neuen Wert addieren 
und den ältesten zu subtrahieren. Du kommst so mit 2 Addern aus 
(vergibst Dir aber die Möglichkeit, die Taps in Zukunft zu gewichten).

> Und die Division durch 8 ist viel einfacher als eine Division durch 10.

Falls Du es trotzdem mal genau brauchst: Division durch eine Konstante 
ist nicht so schlimm, das kannst Du immer auf eine Division durch 2^N 
und eine Multiplikation reduzieren...
Moderator (Firma: Titel) Persönliche Seite #3280018
Moritz A. schrieb:
> Du kannst schon vor der Addition jeden Wert durch 8 teilen. Dauert zwar
> ein Moment länger, aber ich glaube nicht dass die Routine hier
> zeitkritisch ist.
In Hardware ist eine Division durch eine Zweierpotenz einfach ein 
festes Umverdrahten. Das braucht überhaupt keine "Rechenzeit"...

Eine Division durch 10 könnte man auch mit einer Multiplikation mit 410 
und anschließendem Abschneiden der unteren 12 Bits hinreichend genau (1 
Promille Fehler) hinbekommen...
Gast #3280035
Lothar Miller schrieb:
> Eine Division durch 10 könnte man auch mit einer Multiplikation mit 410
> und anschließendem Abschneiden der unteren 12 Bits hinreichend genau (1
> Promille Fehler) hinbekommen...

Wo kriegt man eigentlich solche Näherungen her? Reines "Trickreich 
denken" oder gibt es da eine Übersicht über gängige Methoden?

Ich muß gerade an "fast inverse square root" 
(http://en.wikipedia.org/wiki/Fast_inverse_square_root) denken.
#3280044
Nicolas S. schrieb:
> Wo kriegt man eigentlich solche Näherungen her?

Ist überhaupt kein Voodoo, Du willst durch 10 teilen, sprich mit 0.1 
multiplizieren. Jetzt gehst Du wie folgt vor:

1. Multiplizieren mit 2^N * 0.1
2. Weglassen der hintersten N Bits (i.e. teilen durch 2^N)

Den Fehler errechnest Du zu

3. Err = 0.1 / (ganzzahlgerundet(2^N*0.1) / 2^N)

So und jetzt musst Du nur noch N bestimmen, so klein wie möglich 
(Aufwand), so gross wie nötig (Fehler).
Gast #3280053
Mir ist schon klar, daß der Bruch a/b durch c/(2^d) angenähert wird und 
ich für jedes d ein c finde, das den Fehler minimiert.

Aber wo lernt man solche Tricks?
Gast #3280728
Lothar Miller schrieb:
> Eine Division durch 10 könnte man auch mit einer Multiplikation mit 410
> und anschließendem Abschneiden der unteren 12 Bits hinreichend genau
Na dann aber lieber mal 1638 und zwei Bit mehr weg. Das sind dann 
wirkliche 0,1%

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 13 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.