Forum: Digitale Signalverarbeitung / DSP / Machine Learning FFT mit dsPIC


von Benedikt K. (benedikt)


Angehängte Dateien:

Lesenswert?

Ich versuche schon seit Tagen das Beispielprogramm von Microchip zum 
Laufen zu bekommen.
Ich habe das Programm ein wenig aufgeräumt und übertrage die Kurvenform 
(im Moment ein einfacher Sinus von 0-5kHz, 10kHz Samplerate) vom PC zum 
dsPIC und das Ergebnis vom dsPIC geht zurück zum PC wo die Werte 
grafisch dargestellt werden.
Das Hamming Fenster passt noch, auch die Umsortierung der Werte in 
Komplexe Werte müsste noch OK sein.
Das Ergebnis der FFT ist aber nicht so ganz das was ich von einem Sinus 
erwarte. Wenn ich die Frequenz von 0-5kHz durchlaufen lasse, müsste 
eigentlich eine Spitze von links nach rechts laufen, aber die Spitzen 
springen hin und her, und es sind immer mehrere große und eine Menge 
kleiner Spitzen.

von Matthias (Gast)


Lesenswert?

Ich habe den Code jetzt nich angesehen, aber folgendes: Die zwei Spitzen 
beim Sinus erkennst du nur, wenn deine Abtastrate ein ganzes Vielfaches 
der Sinus Frequenz ist (=> kohärente Signalverarbeitung), sonst geht das 
bei der Transformation nicht auf, und du kriegst mehrere Spitzen.

Also für 1kHz, 2kHz, 5kHz usw. sollte es stimmen, bei 1.5kHz kriegst du 
nicht das ideale Spektrum. Hat mit der Fensterung und der 
darauffolgenden Abtastung an falschen Stellen zu tun, siehe zB 
picket-fence-effect.

Wenn es für ein 1kHz Signal immer noch nicht funktioniert, kann das 
folgende Gründe haben: Abtastrate und Signalfrequenz sind leicht 
asynchron, das kann dann immer noch schweinerein geben. Oder aber dein 
Algorithmus ist falsch.

von Benedikt K. (benedikt)


Lesenswert?

Sollte die Fensterung vor der FFT diese Probleme nicht beheben ?
Ich habe schon mit anderen FFT Algorithmen gearbeitet, da hatte ich 
solche Probleme nie, zumindest nicht in diesem Umfang. Außerdem sind die 
Werte die aus der FFT herauskommen recht gering: Aus der FFT kommen 16 
bit Werte heraus,  Werte größer +-400 kommen aber nie raus, selbst bei 
einem Sinus mit voller Amplitude als Eingangssignal.
Der jetzige FFT Algorithmus stammt von Microchip, der sollte also OK 
sein. Die Schwierigkeit besteht jetzt nur, diesen anzuwenden.

von Matthias (Gast)


Lesenswert?

Nein, eine Fensterfunktion beseitigt solche Probleme nicht, sondern 
verringert lediglich die Energie in den Nebenmaxima und erhöht damit die 
Ablesbarkeit etwas.
Wie gesagt, übertrage mal einen geeigneten Sinus. Also wenn du zB ne 
1024 Punkt FFT machst, dann nimm ne Sinus Periodenlänge von 128 oder 256 
Punkten.
Nur bei solchen geraden vielfachen wirst du nur mit Punkte im Spektrum 
haben, bei denen die Leistung > 0 ist. Ansonsten gibt es immer ein 
breiteres Spektrum.

Gut wäre es, wenn du das Spektrum deines Signals noch parallel in Matlab 
oder so berechnen könntest. Dann würdest du sehen, ob dein Pic Programm 
falsch liegt, oder die Darstellung eben normal ist, aufgrund des 
Eingangssignals.

von Benedikt K. (benedikt)


Angehängte Dateien:

Lesenswert?

Hier mal das Signal (linke 256 Werte) und das Ergebnis (rechte 256 
Werte). Das Signal müsste sich periodisch ohne großen Versatz fortsetzen 
lassen. Das Ergebnis sieht meiner Meinung nach etwas merkwürdig aus.

von Benedikt K. (benedikt)


Angehängte Dateien:

Lesenswert?

Hier zum Vergleich mit Matlab. So sieht es schon besser aus. Diesmal 
sogar ohne Fensterung.

von Matthias (Gast)


Lesenswert?

Also am Abbruchfehler liegts damit nicht. Du könntest mal noch ne höhere 
Amplitude des Signals versuchen, oder auch ne niedrigere. Das könnte 
helfen wenns am Problem der Rechengenauigkeit oder Übersteuerungen 
liegt.
Ansonsten liegt der Fehler wohl irgendwie im Code. Sehe dort nix 
auffälliges, habe aber auch keine Ahnung vom dspic

von Benedikt K. (benedikt)


Lesenswert?

Danke für die Hilfe.
Anscheinen sind die dsPICs nicht wirklich weit verbreitet.

Die Amplitude habe ich auch schon verändert, aber auch das bringt 
nichts.


von Franko P. (sgssn)


Lesenswert?

Hallo

ich bin auch nicht der dsPIC/DSP - Profi, aber müssen die Daten, die in 
die FFT geschickt werden, nicht vom Typ "fractional" sein ? Ich kann 
nicht erkennen, von welchem Typ deine Daten sind.


Gerhard

von Benedikt K. (benedikt)


Lesenswert?

Die Daten sind Fractional Complex (es sind globale Variablen, stehen 
zwischen main und den Kommentaren). Diese entsprechen aber int, nur der 
beim Lesen ist der Wertebereich eben -1...+1 und nicht -32768...+32767. 
Ist reine Definintionssache.

von Aufreger deluxe (Gast)


Lesenswert?

Poste mal in forum.microchip.com.

von Franko P. (sgssn)


Lesenswert?

Hi

ich will nicht nerven, aber ich seh nur, dass die Daten über den UART 
eingelesen werden. Und ich meine, dass ich mal gelesen hab, dass die 
Daten für die FFT nicht zwischen -1 und +1 liegen dürfen, sondern nur 
zwischen -0,5 und +0,5. Ich schliesse mich "Aufreger deluxe" an und 
empfehle das http://forum.microchip.com. Wenn die Leute dort gut drauf 
sind, helfen Sie dir sogar. Du kannst aber auch mal nach FFT suchen, da 
gibt vermutlich genug die das gleiche Prob haben.

Gerhard

von Benedikt K. (benedikt)


Lesenswert?

>Und ich meine, dass ich mal gelesen hab, dass die Daten für die FFT nicht 
zwischen -1 und +1 liegen dürfen, sondern nur zwischen -0,5 und +0,5.

Richtig, daher multiplizierte ich den 8bit Wert vom UART auch nicht mit 
256 sondern nur mit 100 um auf der sicheren Seite zu sein.

von uu (Gast)


Lesenswert?

Und weshalb kann das UART keine 16bit Werte uebertragen ?
Sollte allerdings nicht viel machen. Wenn der Wertebereich nur ein 
aufgeblasener 8 bit Bereich ist, gibt es mehr Oberwellen. Das waeren 
dann ganzzahlige Vielfache.

uu

von Benedikt K. (benedikt)


Lesenswert?

Ich verwende nur 8bit Werte, da es einfacher ist und ich so Probleme 
durch vertauschte High/Low Bytes sicher ausschließen kann.

von reimay (Gast)


Lesenswert?

Hallo Benedikt,
ich habe gerade ein ähnliches Problem mit den dsPICs.

Ich kann nicht nachvollziehen was in der SquareMagnitudeCplx (...)
gerechnet wird.

Wenn ich im Simulator das Beispielprogramm von Microchip
bis nach dem Aufruf von
 BitReverseComplex (LOG2_BLOCK_LENGTH, &sigCmpx[0]);
laufen lasse und den Absolutwert manuell berechne,
bekomme ich das erwartete Ergebnis. ( getestet mit dirac,DC und einer 
cos-
funktion.)

Ich habe noch nicht weiter in die SquareMagnitudeCplx () hinein 
gedebuggt,
weil es mir im Moment nicht so wichtig ist.

Hole Deine Daten doch mal vor der Betragsbildung ab,
es würde mich interessieren ob sich dann das Ergebniss verbessert.


Viele Grüsse,
reimay

von Benedikt K. (benedikt)


Lesenswert?

Wenn ich den Betrag am PC aus dem komplexen Daten berechne sieht das 
Ergebnis genauso aus, wie das Ergebnis von SquareMagnitudeCplx().
Daran liegt es also (zumindest bei mir) nicht.
Der Fehler muss also während der FFT oder dem Umsortierten der Bits 
entstehen.

Beim FFT Beispielprogramm, dass die Grundfrequenz herausfindet ist es 
anscheinend Zufall, dass das richtige Ergebnis rauskommt.

von Unit (Gast)


Lesenswert?

Hallo,

diesen Sommer hab ich mit einem dsPICDEM Board "gespielt". Allerdings 
hab ich auch den A/D und das LCD, die auf dem Board sind, benutzt. Mit 
der FFT-Function von Microchip hatte ich das Problem, dass das 
Vorzeichen des imaginären Teils im Ergebnis nicht immer korrekt war. 
Besser gesagt, das ist kein richtiges Problem, weil 
SquareMagnitudeCplx() macht sowieso ^2.
Zu SquareMagnitudeCplx(): diese Function macht folgendes: Re(x(k))^2 + 
Im(x(k))^2, also sqrt macht sie nicht, das musst du mit Matlab 
korrigieren.
Ich vermute, dass bei einer Auflösung von 8 Bits (USART) das 
Quantisierungsrauschen so gross ist, dass das schon in so einem 256 
langen FFT zu erkennen ist.
Mein Vorschlag: mach mit MATLAB so ein Signal (besser gesagt: einen 
Vektor), das nur aus ganzen Perioden besteht. So kannst du Leakage 
vermeiden. Dann lass die Fensterfunktionen aus dem Code raus, mal sehen, 
was dann passiert.

Gruss,

Unit*

von Unit (Gast)


Lesenswert?

PS: Leakage kannst du in diesem Fall mit Sicherheit nicht haben, weil 
dein Programm auf jedes Sample wartet... Also wenn das Inputsignal eine 
ganze Anzahl von Perioden hat, und es keine Datenverluste geben, ist es 
unmöglich.

von Benedikt K. (benedikt)


Lesenswert?

Wenn SquareMagnitudeCplx keine Wurzel zieht, dann passt da irgendwas mit 
Sicherheit nicht in der FFT Routine: Die Ergebnisse von 
SquareMagnitudeCplx sind bei mir alle kleiner als 256. Wenn ich daraus 
noch die Wuzel ziehe, komme ich auf einen Wertebereich von 0-15. Und 
eine Amplitude von 15 ist definitiv falsch, bei einem Sinus mit 
maximaler Amplitude als Eingangssignal.

von Unit (Gast)


Lesenswert?

Mit Sicherheit zieht SquareMagnitudeCplx() keine Wurzel. Das kannst du 
mit dem MPLAB Simulator ausprobieren (Debugger/Select Tool/MPLAB SIM). 
Der Code dafür:

#include <p30Fxxxx.h>
#include <dsp.h>

fractcomplex in[2] _attribute_ ((section (".ydata, data, ymemory"))) = 
{0x2000,0x2000};
fractional out[1] _attribute_ ((section (".ydata, data, ymemory")));

int main(void)
{
  SquareMagnitudeCplx(8, in, out);
}

Nach Build und Run geh auf View/Watch, dort suche "out" aus, dann klicke 
auf "Add Symbol". Das Ergebnis ("in") ist 0x1000 (two's complement, hexa 
signed fractional), das gleich 0.125 (Dezimal) ist. Was ich geschrieben 
habe ist richtig, weil .25^2 + .25^2 = .125.

Zu deinem letzten Beitrag: die Größe der Diracs im Spektrum (wenn es 
kein Leakage gibt) sollten 1/N *A*N/2 = A/2 sein, daher hast du Recht. 
Aber was für Daten kommen durch den UART? Ich vermute, dass der DSP die 
Daten aus dem PC (bzw. von MATLAB) ohne Umwandlung bekommt. Wenn das so 
ist, dann brauchst du "-128" nicht:

p_real[i] = ((signed int)(uart_getchar()-128))*100;

Das verursacht Unlinearitäten im Signal (two's complement overflow), und 
harmonics im Spektrum, wie auf fft_dspic.gif
An deiner Stelle würde ich folgendes machen: mit MATLAB die 
Datenkonversion erledigen (der MATLAB rechnet mit signed int, der DSP, 
bzw die Funktionen brauchen fractional, eine MATLAB Funktion zu 
schreiben braucht keine Minute), *100 versaut die Vorzeichen 
(fractional!!!) ich würde *256 schreiben und mit MATLAB die Datengröße 
limitieren, statt "signed int" kommt "fractional". Benutze zuerst keine 
Fensterfunktionen (überfüssige Fehlerquelle), die Ergebnisse der FFT 
ebenfalls mit MATLAB zurückkonvertieren.

von Benedikt K. (benedikt)


Lesenswert?

So wie ich fractional verstanden habe, ist es nichts anderes als "signed 
int"/32768.

Ein signed int Wert 32767 entspricht somit 0,99996948 und -32768 als 
fractional interpretiert wäre -1.
Beide Zahlenformate sind also gleich, nur auf einen anderen Wert 
normiert.

Oder habe ich das falsch verstanden ? Dann würde ich nämlich auch die 
Ergebnisse falsch interpretieren was diese Fehler erklären würde.

von Unit (Gast)


Lesenswert?

Du hast es richtig verstanden. Was aber du nicht betrachtest (und der 
Sinn der ganzen Sache ist), daß two's complement fractional 
left-justified ist! Das heißt (nehmen wir zB 4 Bits):

1100 0000 (fractbin) = C0 (fracthex) = 1*(-2^0) + 1*2^-1 + 0*2^-2 + 
0*2^-3 + ... = -.5 (fractdec)

Deswegen sind die beiden Zehlenformate gleich dargestellt, aber anders 
interprtiert. Der DSP hat nicht die leiseste Ahnung, was fractional ist, 
*100 macht er mit der Gewißheit, das er mit ganzen Zahlen zu tun hat.

zB 80 (fracthex) * 100 (dec) = 3200 (fracthex) = +0.3906 (fractdec) 
obwohl 80 (fracthex) = -1 (fractdec) ist!

Wenn du einfach folgendes machen würdest, wäre dein Problem 
wahrscheinlich gelöst: mit MATLAB auf fracthex konvertieren, und über 
den UART schicken, dann im DSP mit 256 multiplizieren (dh << 8).

zB.: C0 (fracthex) * 256 (dec) = C000 (fracthex) = -.5 (fracthex)

Gruß,

Unit*

von Wetterfrosch (Gast)


Lesenswert?

Hi
Ist zwar ein alter post aber vieleicht hilfts mal jemandem.
Die twiddlefactors von Microchip sind falsch.
diese mal updaten und nochmals versuchen.

Benedikt - "Der jetzige FFT Algorithmus stammt von Microchip, der sollte 
also OK sein." Diese Annahme ist ein schwerwiegender Fehler. Siehe die 
ganzen errata listen von Microchip...

von Benedikt K. (benedikt)


Lesenswert?

Wo bekommt man die richtigen twiddlefactors her ? Mir fehlt leider das 
Wissen um diese selbst zu berechnen.

von pumpkin (Gast)


Lesenswert?

Je nachdem wieviele Punkte deine DFT/FFT hat musst du den Einheitskreis 
der komplexen Ebene wie einen Kuchen zerteilen. Beispiel: 4 
twiddle-Faktoren aus dem Einheitskreis sind [+1, +j, -1, -j]. Beispiel: 
8 twiddle-Faktoren: [+1, 0.7+j0.7, +j, -0.7+j0.7, -1, -0.7-j0.7, -j, 
0.7-j0.7]. Mathematisch bedeutet dies: W_N = exp(-j*2*pi/N).

pumpkin

von Unit (Gast)


Lesenswert?

Jaja, aber die FFT-Funktion von Microchip will nur die Hälfte dieser 
Punkte haben (genauer gesagt von n=0 bis n = floor((N-1)/2))!!!
Die genaue Berechnung:

twid(n) = exp(-j*2*pi*n/N)

n = 0 .. N-1

z.B. N = 4:

twid(0) = exp(0) = 1
twid(1) = exp(-j*2*pi*1/4) = exp(-j*pi/2) = -j
twid(2) = exp(-j*2*pi*2/4) = exp(-j) = -1
twid(3) = exp(-j*2*pi*3/4) = exp(-j*3*pi/2) = +j

In disem Fall brauchst du nur twid(0) und twid(1), da der Rest 
"symmetrisch" ist, nur die Vorzeichen sind umgekehrt.

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.