Forum: Digitale Signalverarbeitung / DSP / Machine Learning Pyfda und die Amplitude


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Hallo,

ich verwende gerne Pyfda https://github.com/chipmuenk/pyfda zum Entwurf 
von Filtern. Aber ich habe ein Problem das ich nicht verstehe:

Die Amplitude im Passband ist nicht gleich der Eingangsamplitude sondern 
oft deutlich niedriger, teilweise nur die Hälfte. Und das obwohl das 
Filter so entworfen wurde, dass das Signal dort nicht gedämpft wird.
Mir ist klar, dass es im Passband oft Ripple gibt, aber eine Dämpfung im 
gesamten Passband finde ich seltsam.

Aber vielleicht ist ja auch einer meiner Schritte falsch:
Ich entwerfe das Filter wie im ersten Bildchen Filter_1.
Dann stelle ich ein, dass die Koeffizienten Integers mit maximal 16 Bits 
sind. Also signed wie im Bildchen Filter_2.
Seltsam ist, dass trotz der 16 Bits der maximale Wert der Koeffizienten 
hier bei nur 8192 liegt. Das ist 2**13 und etwas wenig. Der maximale 
positive Wert bei 16 Bit signed ist ja 2**15-1.
Die Koeffizienten kopiere ich dann in das FIR Filter und bekomme eben 
als Ergebnis ein gefiltertes Signal mit deutlich reduzierter Amplitude 
im Passband.
Wenn ich aber alle Koeffizienten so skaliere, dass sie die vollen 16 
Bits ausnutzen ändert das nix an der Amplitude. Ist ja auch 
verständlich, denn es werden ja positive und negative Koeffizienten 
skaliert. Die gewichtete Summe bleibt also gleich.

Aber wo kommt das her und wie schaffe ich es die Amplitude zu erhöhen? 
Klar könnte ich das Ergebnis, also das gefilterte Signal multiplizieren, 
aber dazu sehe ich keinen Grund wenn das Filter das ebenfalls können 
müsste.

von Detlef _. (detlef_a)


Lesenswert?

Gustl B. schrieb:
> Wenn ich aber alle Koeffizienten so skaliere, dass sie die vollen 16
> Bits ausnutzen ändert das nix an der Amplitude. Ist ja auch
> verständlich, denn es werden ja positive und negative Koeffizienten
> skaliert.

Nein. Wenn Du die Koeffizienten skalierst muss die Amplitude mitgehen. 
Du hast wahrscheinlich Overflows bei den Zwischenwerten.

Cheers
Detlef

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Nun, ich verwende das Filter von Xilinx. Da erwarte ich schon, dass das 
richtig funktioniert. Seltsam ist auch, dass das unterschiedlich 
aussieht wenn ich das in Pyfda oder im Xilinx Tool angucke. Bei dem 
Xilinx Tool verstehe ich die Achsenbeschriftung nicht. Also wo die den 
Nullpunkt der y-Achse hingelegt haben.

Die Koeffizienten:

0,0,0,0,-2,-4,-5,0,15,32,34,0,-72,-143,-139,0,249,463,427,0,-713,-1306,- 
1211,0,2290,5054,7318,8192,7318,5054,2290,0,-1211,-1306,-713,0,427,463,2 
49,0,-139,-143,-72,0,34,32,15,0,-5,-4,-2,0,0,0,0

Es stimmt, doch, dass ich die Nullen am Anfang und am Ende weglassen 
kann oder?

Detlef _. schrieb:
> Nein. Wenn Du die Koeffizienten skalierst muss die Amplitude mitgehen.

Das stimmt natürlich. Ich hatte nur den Fall betrachtet wenn die Summe 
der Koeffizienten Null ist. Dann ändert sich DC nicht wenn man die 
Koeffizienten skaliert. Aber für höhere Frequenzen ändert sich dann 
schon die Amplitude, das hatte ich nicht bedacht.

: Bearbeitet durch User
von Dergute W. (derguteweka)


Lesenswert?

Moin,

Gustl B. schrieb:
> Bei dem
> Xilinx Tool verstehe ich die Achsenbeschriftung nicht. Also wo die den
> Nullpunkt der y-Achse hingelegt haben.

Summier' alle Koeffizienten mal auf, das ist ja dann das, was aus dem 
Filter rauskommt, wenn man es mit einem Einheitssprung, also sowas wie 
Gleichspannung, anregt.
Das ist dann also die Zahl, die aus dem Filter mit jedem Takt rauskommt. 
Und wenn du diese Zahl logarithmierst und das dann x20 nimmst...

Die Unterschiede im Sperrverhalten in den Diagrammen sehen so aus, als 
ob Xilinx mit den auf Bitaufloesung gerundeten Koeffizienten arbeitet 
und Pyfda mit Floatingpoint.

Gruss
WK

von Gustl B. (-gb-)


Lesenswert?

Dergute W. schrieb:
> Summier' alle Koeffizienten mal auf

32766

Das ist also fast 2**15.

Dergute W. schrieb:
> Und wenn du diese Zahl logarithmierst

4.515423

Dergute W. schrieb:
> und das dann x20 nimmst...

90.30846

Ja, fein. Das passt zu dem was mir das Xilinx Tool anzeigt. Aber wie 
ändere ich die Amplitude?

Ich habe auch schon alle Koeffizienten mit 1,5 multipliziert.

0, 0, 0, 0, -3, -6, -7, 0, 22, 48, 51, 0, -108, -214, -208, 0, 373, 694, 
640, 0, -1069, -1959, -1816, 0, 3435, 7581, 10977, 12288, 10977, 7581, 
3435, 0, -1816, -1959, -1069, 0, 640, 694, 373, 0, -208, -214, -108, 0, 
51, 48, 22, 0, -7, -6, -3, 0, 0, 0, 0

Dann sagt mir das Xilinx Tool und die selbe Rechnung wie oben 93.83. 
Aber die Amplitude in der Simulation ändert sich genau nicht.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Gustl B. schrieb:
> Dann sagt mir das Xilinx Tool und die selbe Rechnung wie oben 93.83.
> Aber die Amplitude in der Simulation ändert sich genau nicht.

Die 93.83 passen ja zum Faktor 1.5.
Warum das bei der Simulation nix aendert? keinen Blassen...

Gruss
WK

von Detlef _. (detlef_a)


Lesenswert?

Gustl B. schrieb:
> Nun, ich verwende das Filter von Xilinx. Da erwarte ich schon, dass das
> richtig funktioniert.

Sicher funktioniert das. Aber Du hast bei der Bedienung irgendeinen 
Fehler gemacht oder was mißverstanden. Jetzt gibs zwei Möglichkeiten: 
entweder fummelst Du Dich in die Xilinx tools rein und findest den 
Fehler oder Du bastelst selber nen FIR in Verilog oder VHDL zusammen. 
Mach Letzteres, weil dann hast Du nicht lediglich die tools verstanden 
sondern kannst FIR, egal in welcher Implementationssprache. So hab ich 
das gemacht, und FIR kann ich :)))

Cheers
Detlef

von Gustl B. (-gb-)


Lesenswert?

Detlef _. schrieb:
> oder Du bastelst selber nen FIR in Verilog oder VHDL zusammen.

Das hatte ich schon gemacht. Und zwar in mehreren Formen je nachdem was 
man will, wenig DSPs oder höhere Samplerate. Siehe 
Beitrag "FIR parallel und seriell braucht zu viele LUTs."

Aber der Xilinx FIR Compiler IP der optimiert halt doch besser. Den 
würde ich gerne verwenden. Klar, kann ich machen und am Ende das 
Ergebnis passend skalieren, aber das sollte doch auch ohne so eine 
Skalierung funktionieren.

von Christian M. (chipmuenk)


Angehängte Dateien:

Lesenswert?

Hallo Gustl,
bin gerade zufällig über diesen Thread hier gestolpert (nein, ich habe 
kein Ego-Googling gemacht ;-)). Ich bin der Hauptentwickler von pyFDA 
und wollte mich demnächst mit der Skalierung der Koeffizienten 
beschäftigen. Das ist noch verbesserungswürdig und daher wäre ich an 
Feedback interessiert.

Ich habe mal eine kurze Fixpointsimulation mit dem 
Default-Equiripplefilter und 16 bit Koeffizienten gemacht. Bei der 
Sprungantwort ("Step") musste ich die Amplitude auf 0.9 reduzieren um 
Überläufe zu verhindern.

Schick mir doch die Filterdaten wenn Du magst, dann kann ich mir das mal 
anschauen.

Viele Grüße,

Christian

von Gustl B. (-gb-)


Lesenswert?

Christian M. schrieb:
> bin gerade zufällig über diesen Thread hier gestolpert

Juhu wie fein! Deine Videoreihe habe ich mir vor einiger Zeit mal auf 
Youtube angeguckt, vielen Dank!

Naja, eigentlich möchte ich mal FIR zu Fuß machen und das dann auch 
verstanden haben.

Meine aktuelles Verständnis ist, dass das so geht:
Ich habe ein Array mit Abtastwerten (ungefiltert), ich habe ein kürzeres 
Array mit Koeffizienten (koeffizienten).
Jetzt schiebe ich schrittweise die Koeffizienten an den Abtastwerten 
entlang. Immer wenn ich die um einen Schritt geschoben habe, dann mache 
ich:
1
gefiltert = []
2
schieberegister = [0]*len(koeffizienten)
3
for i in range(0,len(ungefiltert)):
4
  schieberegister.pop(0)
5
  schieberegister.append(ungefiltert[i])
6
  summe = 0
7
  for j in range(0,len(koeffizienten)):
8
    summe += koeffizienten[j] * schieberegister[j]
9
    gefiltert.append(summe/len(koeffizienten))
Und meine Annahme ist, dass wenn das Filter im Durchlassbereich eine 
Dämpfung von 0 dB hat, dann bleibt die Amplitude so wie beim 
ungefilterten Eingangssignal.

Jedoch sehe ich das nicht so wenn ich das zu Fuß hinschreibe.

Koeffizienten (Bandpass, DEC, Integer, W=16) sind z. B.:
koeffizienten = 
[0,-1,0,0,-2,-1,7,16,10,-13,-29,-20,3,7,-9,-5,38,75,43,-49,-106,-66,10,2 
2,-25,-14,104,199,110,-120,-255,-157,23,50,-55,-31,227,431,236,-255,-537 
,-329,50,106,-115,-64,480,917,507,-554,-1189,-742,116,253,-285,-165,1325 
,2720,1654,-2040,-5186,-4153,988,5848,5848,988,-4153,-5186,-2040,1654,27 
20,1325,-165,-285,253,116,-742,-1189,-554,507,917,480,-64,-115,106,50,-3 
29,-537,-255,236,431,227,-31,-55,50,23,-157,-255,-120,110,199,104,-14,-2 
5,22,10,-66,-106,-49,43,75,38,-5,-9,7,3,-20,-29,-13,10,16,7,-1,-2,0,0,-1 
,0]

Was ich gerne sehen würde wäre ein sehr einfacher Code ohne eine fertige 
Bibliothek wie eben mein Code oben der einen FIR zu Fuß rechnet.
Ich habe FIRs auch schon in VHDL geschrieben sowohl seriell als auch als 
Pipeline ( Beitrag "Re: zu blöd für 25 tap FIR auf FPGA" ) aber 
ich musste bisher das Ergebnis immer skalieren. Es reichte nicht die 
Summe durch die Anzahl der Koeffizienten zu teilen.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Gustl B. schrieb:
> Was ich gerne sehen würde wäre ein sehr einfacher Code ohne eine fertige
> Bibliothek wie eben mein Code oben der einen FIR zu Fuß rechnet.

Sowas?
1
/* compile with:
2
  gcc -Wall -O2 bla.c -lm
3
 */
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <math.h>
7
8
double sinc(double s) {
9
    if (s) return sin(s)/s;
10
    return 1.0;
11
}
12
int fir(int n, double w, double * coeff) {
13
    int i;
14
    double x;
15
    for (i=0; i<=n; i++) {
16
        /* here happens the filter magic: */
17
        x = i-n/2.0;
18
        x *= M_PI * w;
19
        coeff[i] = sinc(x);
20
    }
21
    return 0;
22
}
23
int main(int argc, char* argv[]) {
24
    int n = 6;
25
    double w=0.5;
26
    double * coeff;
27
    double sum = 0.0;
28
    int i;
29
    if (argc < 3) printf("usage: %s n w\n using order n=%d, normalized cutoff freq. w=%g as default\n", argv[0],n,w);
30
    if (argv[1]) {
31
        n = atoi(argv[1]);
32
        if (argv[2]) {
33
            w = strtod(argv[2], NULL);
34
        }
35
    }
36
    coeff = calloc((n+1),sizeof(double));
37
    if (!coeff) {
38
        printf("phuc!\n");
39
        return -1;
40
    }
41
    fir(n, w, coeff);
42
    /* normalize + print coefficients */
43
    for (i=0;i<=n;i++) {
44
        sum += coeff[i];
45
    }
46
    for (i=0;i<=n;i++) {
47
        printf("%g\n",coeff[i]/sum);
48
    }
49
    free(coeff);
50
    return 0;
51
}

Gruss
WK

von Gustl B. (-gb-)


Lesenswert?

Ne, nicht sowas. Das berechnet doch die Koeffizienten wenn ich das 
richtig verstanden habe und zwar als Double?

Ich suche einen FIR Filter, also eine Funktion die eine unendliche Folge 
aus Abtastwerten nacheinander an festen Koeffizienten vorbeischiebt, 
multipliziert, summiert und je Schritt einen Ausgangswert ausgibt.

Aber:
- Mit ganzzahligen Koeffizienten und
- die Amplitunde sollte stimmen.

Mir ist mittlerweile klar, dass mein Problem durch die Verwendung von 
Integerkoeffizienten herkommt. Das möchte ich nicht ändern sondern 
weiterhin Integer verwenden. Ich will aber herausfinden wie ich einen 
Faktor berechne mit dem ich die Amplitude korrekt hinbekomme.
Nach den Multiplikationen bilde ich die Summe. Und diese will ich mit 
einem Faktor skalieren damit die korrekte Amplitude herauskommt.

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Axo. Die Funktion, die du suchst, heisst Faltung(convolution).
Danach brauchst du noch eine Skalierung. Bei Tiefpaessen kriegst du den 
Faktor ueber die Summe der Koeffizienten. Bei anderen -paessen wirds 
etwas unangenehmer. Wahrscheinlich musst du dann die Koeffizienten noch 
mit einem cos() Signal mit 0/Mittenfrequenz/halben Abtastfrequenz 
multiplizieren, danach aufsummmieren fuer die Skalierung auf 1 bei 
0/Mittenfrequenz/halbe Abtastfrequenz.
Da emfehl' ich mal ein Grundlagenbuch fuer Signalverarbeitung, wo 
Faltung, Impulsantwort, etc. durchgekaut wird.

Gruss
WK

von Gustl B. (-gb-)


Lesenswert?

Dergute W. schrieb:
> Die Funktion, die du suchst, heisst Faltung(convolution).

Ja das ist die Multiplikation und Summenbildung. Das habe ich schon.

Dergute W. schrieb:
> Danach brauchst du noch eine Skalierung. Bei Tiefpaessen kriegst du den
> Faktor ueber die Summe der Koeffizienten. Bei anderen -paessen wirds
> etwas unangenehmer.

Exakt darum geht es mir. Bisher mache ich das durch Probiererei. Ich 
würde das aber gerne rechnen.

Dergute W. schrieb:
> Da emfehl' ich mal ein Grundlagenbuch fuer Signalverarbeitung, wo
> Faltung, Impulsantwort, etc. durchgekaut wird.

Hm ... na gut, werde ich machen wenn ich Zeit habe. Ausprobieren ist 
bisher ein guter Kompromiss.

von Christian M. (chipmuenk)


Lesenswert?

Eine große Schwierigkeit bei Fixpointfiltern ist immer die Skalierung: 
Bei einem Floating Point Tiefpass-FIR Filter sind die Koeffizienten 
normalerweise so ausgelegt, dass ein Gleichsignal (lauter "Einser") auch 
zu lauter "Einsern" am Ausgang führt (Verstärkung 1 bei DC).

Beispiel: Moving Average Filter mit 4 Taps: Jeder Koeffizient ist b_i = 
0.25, bei einem Gleichsignal erhält man am Ausgang 4 x 0.25 = 1. (Ja, in 
der Praxis skaliert man eher einmal am Ein- oder Ausgang mit 0.25 ...)

Beim gleichen Filter in  Fixpoint-Implementierung mit 8 Bit breiten Ein- 
und Ausgangssignalen muss ich zunächst mal ein Datenformat festlegen. 
Ich wähle Q0.7 mit einem Vorzeichenbit, 0 Vorkommabits und 7 
Nachkommabits. Meine Koeffizienten wären dann z.B. b_i = 0.010_000_0, 
mein Eingangs-Gleichsignal z.B. eine Sequenz von 0.100_000_0 (entspricht 
1/2). Ein Eingangswert 1.000_000_0 entspricht nicht +1 sondern -1 und 
wäre daher schon zu groß, mein Wertebereich ist -1 ... 1 - 1/128 
(1.000_000_0 ... 0.111_111_1).

Bei der Multiplikation wächst die Wortlänge (genau wie bei einer 
dezimalen Multiplikation) sowohl bei Vor- als auch bei Nachkommastellen:

23,45 x 67,89 = 1592,0205

Falls ich nur 4 Dezimalstellen zur Verfügung habe, muss ich Stellen 
nach der Multiplikation wegwerfen (mache ich das vorher, leidet die 
Genauigkeit). Da ich die Vorkommastellen ausgenutzt habe (keine 
Reserve), muss ich die Nachkommastellen fallen lassen bzw. runden.

Genau das Gleiche muss ich auch bei meinem Fixpointfilter tun. Nach der 
Multiplikation habe ich 4 Teilprodukte mit jeweils 0.001_000_000_000 
(entspricht 1/8) im Format Q0.14 (15 Bit) oder wenn ich ganz genau bin 
im Format Q1.14, da das Produkt -1 x -1 = +1 eine Extra-Vorkommastelle 
bräuchte.

Addiere ich meine 4 Teilprodukte auf (dafür brauche ich in unserem Fall 
Addierer mit 14 Nachkommabit und 1 Vorkommabit, bei anderen 
Koeffizienten u.U. auch mehr Vorkommabits. Da ich am Ausgang nur 8 Bits 
zur Verfügung haben, muss ich wieder im Dezimalbeispiel Bits wegwerfen, 
wieder im Nachkommabereich.

@Gustl B.: Wenn Du Dich jetzt fragst, was das mit Deinem Problem zu tun 
hat: Digitale Rechenwerke kennen kein Komma, für ein FPGA ist 
0.111_111_1 das Gleiche wie 0111_111_1, das Komma ist nur in Deinem 
Kopf! Du musst in einem Fixpoint-Filter darauf achten, die Daten richtig 
zu kürzen und anzuordnen und ggf. zu verlängern (Sign Extension). Mein 
Kollege entwirft seine Digitalfilter lieber im Integerformat, ich komme 
besser mit dem Fractional Fixpoint Format klar. Auf dem FPGA sind die 
Filter aber gleich.

Mehr Info:
* http://www.digitalsignallabs.com/fir.pdf
* 
https://github.com/chipmuenk/dsp/blob/main/notebooks/07_FIX/FIX_intro.ipynb 
(Jupyter Notebook)
* 
https://github.com/chipmuenk/dsp/blob/main/docs/DSV_FPGA_Muenker_Skript.pdf 
(Kap. 6 zu Fixpointformaten und -filtern)

Viel Spaß damit :->

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Vielen Dank für die ausführliche Erklärung!

Christian M. schrieb:
> @Gustl B.: Wenn Du Dich jetzt fragst, was das mit Deinem Problem zu tun
> hat: Digitale Rechenwerke kennen kein Komma, für ein FPGA ist
> 0.111_111_1 das Gleiche wie 0111_111_1, das Komma ist nur in Deinem
> Kopf!

Das ist mir schon bekannt. Ich habe nur noch nicht verstanden wie ich 
ich darauf komme wie viele LSBs ich verwerfe.

Wenn ich als Beispiel Abtastwerte mit 16 Bit habe und ein FIR Filter mit 
64 Koeffizienten die ebenfalls 16 Bits haben, dann bekomme ich für die 
Summe:
16+16+6 = 38 Bits
Damit ich wieder Ausgangswerte mit 16 Bit habe könnte ich einfach die 22 
LSBs wegwerfen. Aber dann passt eben die Amplitude vom Filter nicht.

Auch wenn ich das nicht von Hand schreibe sondern mit dem Xilinx FIR 
Wizard bauen lasse, dann stimmt die Amplitude nicht. Sie ist nicht irre 
weit daneben, aber doch etwas.

Ich habe das jetzt mal mit dem Xilinx FIR in den Anhang gesteckt. Die 
Koeffizienten:
koeffizienten =
[-1,0,0,-2,-1,7,16,10,-13,-29,-20,3,7,-9,-5,38,75,43,-49,-106,-66,10,2
2,-25,-14,104,199,110,-120,-255,-157,23,50,-55,-31,227,431,236,-255,-537
,-329,50,106,-115,-64,480,917,507,-554,-1189,-742,116,253,-285,-165,1325
,2720,1654,-2040,-5186,-4153,988,5848,5848,988,-4153,-5186,-2040,1654,27
20,1325,-165,-285,253,116,-742,-1189,-554,507,917,480,-64,-115,106,50,-3
29,-537,-255,236,431,227,-31,-55,50,23,-157,-255,-120,110,199,104,-14,-2
5,22,10,-66,-106,-49,43,75,38,-5,-9,7,3,-20,-29,-13,10,16,7,-1,-2,0,0,-1 
]

Vielen Dank für die Links! Die werde ich mir mal merken für ruhigere 
Zeiten.

von Christian M. (chipmuenk)


Angehängte Dateien:

Lesenswert?

Sorry, da hatte ich Deine Frage missverstanden. Leider kann man aus der 
Xilinx - Simulation nicht den Faktor ablesen, der Dir an der 
Ausgangsamplitude fehlt. Ich habe Dein Filter nachgebaut und ähnlich 
simuliert wie Du (seit Version 0.4 gibt es Chirp-Stimuli in pyfda). Du 
siehst kaum einen Unterschied zwischen Floating Point und Fixpoint 
Simulation (ich habe die Wortbreiten drastisch reduziert, damit man 
überhaupt etwas sieht). Das letzte Bild zeigt das Filter mit 13 Bit 
Wortbreite am Eingang, 8 Bit Wortbreite der Koeffizienten und 16 Bit am 
Ausgang (bis auf die Wortbreite am Ausgang alles ziemlich beliebig 
gewählt), hier sind alle Signale als "Integer Scale" dargestellt, die 
Amplitude am Ausgang ist ganz knapp noch innerhalb des Wertebereichs. 
Das Eingangssignal habe ich begrenzt ("sat"). Wenn Dein Ausgangssignal 
deutlich kleiner ist, ist wohl noch irgendwas mit Deiner Skalierung im 
Argen.

Mit diesem Teil des Codes habe ich aber auch lange gekämpft, vielleicht 
hilft er Dir ja weiter:

https://github.com/chipmuenk/pyfda/blob/7c8d90e6503d1c3169a09575f4b058133f15cf15/pyfda/fixpoint_widgets/fixpoint_helpers.py#L29

Viel Erfolg!

von Gustl B. (-gb-)


Lesenswert?

Christian M. schrieb:
> Sorry, da hatte ich Deine Frage missverstanden. Leider kann man aus der
> Xilinx - Simulation nicht den Faktor ablesen, der Dir an der
> Ausgangsamplitude fehlt.

Kein Problem. Was der Faktor ist habe ich auch nicht ausgerechnet. In 
dem Bildchen sind aber ungefiltert und gefiltert identisch skaliert. von 
-2**15 bis +2**15-1.

Christian M. schrieb:
> Ich habe Dein Filter nachgebaut und ähnlich
> simuliert wie Du (seit Version 0.4 gibt es Chirp-Stimuli in pyfda). Du
> siehst kaum einen Unterschied zwischen Floating Point und Fixpoint
> Simulation (ich habe die Wortbreiten drastisch reduziert, damit man
> überhaupt etwas sieht). Das letzte Bild zeigt das Filter mit 13 Bit
> Wortbreite am Eingang, 8 Bit Wortbreite der Koeffizienten und 16 Bit am
> Ausgang (bis auf die Wortbreite am Ausgang alles ziemlich beliebig
> gewählt), hier sind alle Signale als "Integer Scale" dargestellt, die
> Amplitude am Ausgang ist ganz knapp noch innerhalb des Wertebereichs.
> Das Eingangssignal habe ich begrenzt ("sat").

Das sieht gut aus, war aber auch zu erwarten. Die Koeffizienten wurden 
mit pyfda berechnet und zeigen mir ja auch eine Dämpfung im 
Durchlassbereich von 0 dB an.

Christian M. schrieb:
> Wenn Dein Ausgangssignal
> deutlich kleiner ist, ist wohl noch irgendwas mit Deiner Skalierung im
> Argen.

Der Witz ist, ich habe da nix skaliert. Ich habe im letzten Post den FIR 
Compiler von Xilinx verwendet und dort nur die Koeffizienten (Integer, 
W=16) aus pyfda hineinkopiert. Dann habe ich noch eingestellt, dass das 
Ausgangssignal 16 Bits signed seien soll und die LSBs verworfen werden.
In der Testbench erzeuge ich einen 16 Bit signed full-scale Sinus Sweep.
Und da kann ich jetzt beobachten, dass die Amplitude geringer ist als 
ich es erwarten würde. Klar könnte ich mir da jetzt den Faktor 
ausrechnen und das selber skalieren, mich würde aber mehr interessieren 
wieso die Amplitude nicht passt. Ist das ein Fehler von dem Xilinx FIR 
Compiler?

Christian M. schrieb:
> Mit diesem Teil des Codes habe ich aber auch lange gekämpft, vielleicht
> hilft er Dir ja weiter:

Werde ich mir mal angucken.

von Christian M. (chipmuenk)


Lesenswert?

Es wäre schon interessant, um welchen Faktor die Antwort in Xilinx zu 
klein ist. Ich weiß nicht, was der FIR-Compiler macht, aber da die 
Multiplizierer je nach Xilinx FPGA 18x18 oder 18x25 Bits verarbeiten, 
könntest Du mal versuchen Deine Koeffizienten als 18 bit signed zu 
erzeugen. Ich habe lange nicht mehr mit dem FIR-Compiler gearbeitet 
(nach meinem letzten frustrierenden Projekt zusammen mit Studis habe ich 
Vivado vom Rechner geworfen und schaue mir gerade den Lattice Flow an), 
aber da gibt es bestimmt Optionen für die Skalierung.

von Gustl B. (-gb-)


Angehängte Dateien:

Lesenswert?

Hm, ja ... jetzt habe ich in die Testbench mal das TextIO eingebaut und 
mir die gefilterten Werte schreiben lassen. Das Maximum hat den Wert 
8434. Das ist also grob 1/4, aber etwas mehr als 1/4.

Dann habe ich mir das mal in Python geschrieben und plotten lassen, da 
passt der Faktor 1/2**15 sehr gut.

Für mich bleibt als Fazit, dass ich nicht verstehe was Xilinx da macht. 
Ich kann damit leben, muss die Ausgangsdaten aber eben manuell 
skalieren.

von Christian M. (chipmuenk)


Lesenswert?

Faktor 4 würde gut zu meiner Idee passen, dass die Koeffizienten um 2 
Bit zu kurz sind. Versuch doch mal, die Koeffizienten mit 18 Bit 
Wortlänge zu Xilinx zu exportieren.

von Gustl B. (-gb-)


Lesenswert?

Gemacht. Das Maximum liegt jetzt bei 66679.
Ich habe Abtastwerte als 18 Bit erzeugt, Koeffizienten in 18 Bit und die 
gefilterten Daten als 18 Bit.

Es bleibt also fast 2 als Faktor. 2 wäre aber zu viel, dann würde es 
clippen.

von Christian M. (chipmuenk)


Lesenswert?

Das Kapitel "Coefficient Quantization" (S. 59 ff.) in

https://www.xilinx.com/support/documentation/ip_documentation/fir_compiler/v7_2/pg149-fir-compiler.pdf

schildert sehr ausführlich, was Xilinx mit den Koeffizienten anstellt. 
Ich wusste z.B. nicht, dass man inzwischen Koeffizienten auch fraktional 
angeben kann. Vielleicht ist die Option "Maximize Dynamic Range" was Du 
suchst.

Und da Du schon so gut in dem ganzen Thema drinsteckst :-> - hast Du 
nicht Lust mich ein bisschen bei der pyFDA-Entwicklung zu unterstützen 
(oder jemand anders hier aus dem Forum)? Ich würde gerne als nächstes 
Fixpointsimulation und -synthese auf nMigen umstellen und auslagern nach 
https://github.com/chipmuenk/pyfixp und 
https://github.com/chipmuenk/dsp_nmigen .

Da die Filter und Fixpointroutinen auch ohne pyfda einsetzbar sein 
sollen, muss man sich in diesen beiden Repos nicht mit der Komplexität 
(= gewachsenes Chaos) von pyfda herumschlagen. Auch Testen von z.B. 
generiertem Verilog-Code und Exportformaten für FIR-Koeffizienten würde 
mir (und der Community ;-) ) weiterhelfen.

von Gustl B. (-gb-)


Lesenswert?

Danke!

Christian M. schrieb:
> Ich wusste z.B. nicht, dass man inzwischen Koeffizienten auch fraktional
> angeben kann.

Das werde ich noch ausprobieren.

Christian M. schrieb:
> Vielleicht ist die Option "Maximize Dynamic Range" was Du
> suchst.

Habe ich schon probiert, ändert nichts.

Christian M. schrieb:
> Und da Du schon so gut in dem ganzen Thema drinsteckst :->

Vielen Dank, aber ich habe da leider nicht wirklich viel Wissen. Ich 
kann VHDL schreiben und habe so auch schon FIR Filter gebaut, sonst bin 
ich da ziemlicher Laie. Ich nutze aber sehr gerne pyfda und finde das 
ein wunderbar schön zu bedienendes nützliches Werkzeug. Danke dafür!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.