FFT mit Python, Problem: Frequenzaufloeseung

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Pretender2k
User
Beiträge: 27
Registriert: Freitag 23. Januar 2009, 18:23

Hallo Zusammen,

auch wenn es vielleicht nicht jedermans Fachgebiet ist, hoffe ich, dass vielleicht der ein oder andere schonmal mit der FFT in Python gearbeitet hat. Ich habe mir, um die FFT erstmal nachvollziehen zu koennen, ein kleines Python Programm geschrieben.

Code: Alles auswählen

from numpy import linspace, array, sin, shape, sqrt
from numpy.fft import fft, fftfreq
from math import pi
from matplotlib.pyplot import figure, plot, show

class FFT_Beispiel(object):
	def __init__(self):
		# Zeit
		self.time = linspace(0,1,2**8)
		
		# Abtastfrequenz
		self.dt = self.time[1]
		self.fa = 1/self.dt

		# Signal1 mit frequenz = f1 und Amplitude = a1
		self.f1 = 2.
		self.a1 = 1.
		self.y1 = array([])
		
		# Signal1 mit frequenz = f1 und Amplitude = a1
		self.f2 = 4.
		self.a2 = 1.
		self.y2 = array([])
		
		# Signal1 mit frequenz = f1 und Amplitude = a1
		self.f3 = 6.
		self.a3 = 1.
		self.y3 = array([])
		
		# Superposition der einzelnen Signale
		self.y = array([])
		
	def signal(self):
		# Berechnung der Signale
		self.y1 = self.a1*sin(2*pi*self.f1*self.time)
		self.y2 = self.a2*sin(2*pi*self.f2*self.time)
		self.y3 = self.a3*sin(2*pi*self.f3*self.time)
		self.y = self.y1 + self.y2 +self.y3
		
	def FFT_Beispiel(self):
		# Berechnung der FFT 
		sp = fft(self.y)
		freq = fftfreq(shape(self.time)[-1], d = self.dt)
		
		# Plotten
		figure(1)
		plot(self.time, self.y1)
		plot(self.time, self.y2)
		plot(self.time, self.y3)
		
		figure(2)
		plot(self.time, self.y)
		
		figure(3)
		plot(freq, sp.real,freq, sp.imag)
		
		figure(4)
		# Betrag berechnen
		spabs = sqrt((sp.real**2) + (sp.imag**2))
		# Normieren auf Amplituden
		spabs = spabs / (shape(self.time)[-1]/2)
		plot(freq, spabs)
		
		show()
		
def main():
	FFT_Exampel =  FFT_Beispiel()
	FFT_Exampel.signal()
	FFT_Exampel.FFT_Beispiel()
Ich habe mit Absicht die Frequenzen und das Zeitfenster fuer die FFT so gewaehlt, dass der Leck-Effekt nicht auftreten sollte. In einem anderen Forum habe ich gelesen, dass die Frequenzaufloesung = (Abtastrate / Anzahl der Werte). Nach dem ich etwas rumprobiert habe, bin ich zu dem Entschluss gekommen, das unter der Frequenzaufloesung wohl die maximal erkennbaren Frequenzen gemeint sind.

Durch die Durchfuerhung der FFT ueber mehrere Perioden des Signals ist mir dann aufgefallen, dass sich dann die Aufloesung auf der X-Achse des Spektrums erhoeht. Bei Wikipedia, hab ich dazu auch irgendwas mit Unschaerferelation der Zeit und Frequenzaufloesung gelesen...?!?

Frage: Da ich besonders gerne die Aufloesung auf der X-Achse des Spektrums erhoehen moechte, wuerde ich gerne wissen, ob das nur moeglich ist ueber einen groesseren Ausschnitt oder ob die Python funktion in dem Fall mir was falsches zurueckgibt bzw. ich die Funktion falsch anwende?

Ich weiss, die Frage ist nicht nur Python spezifisch, aber vielleicht kann mir da jemand trotzdem helfen. Bin ja mit sicherheit nicht der erste hier der ne fft macht :)

THX
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Bin leider nicht zu Hause und kann nur ein Codereading anbieten.
Wie Du weißt muß fa mindest doppelt so hoch wie fmax des Signals sein, um es sicher reproduzieren zu können. Ich denke, das ist bei Dir nicht gegeben.
Fa = 1
fmax = 6
Kann aus meiner Sicht nichts sinnvolles bei rauskommen.
Du erwartest ja sicher drei Linien als Spektrum. Siehst Du sie?
Hast Du schon eine IFFT gemacht? Wie sieht das Signal jetzt aus?
3ff
User
Beiträge: 191
Registriert: Dienstag 22. Dezember 2009, 12:54
Wohnort: Odenwald Sued-Hessen

@Pretender2k
Ich hab 1 Kunden, der macht ab und zu was mit GNU-Radio und braucht deren FastFouriertransformation FFT
Deshalb hab ich grad mal Deine Klasse rübergeladen und versucht zum Laufen zu bringen.
Du benutzt eine matlib, die es in meinem Repository nicht gibt. Figure und plot sind das deine eigenen Funktionen oder C-Funktionen von Python aufgerufen?
Ich arbeite mit Ubuntu 10.04 und mit synaptic. Wir sollten uns da erstmal abgleichen, die FFT gibts auch in cpp. Gnuplot hat auch 1 Klassenbibliothek zum FFT.
Ich könnte Dir die frage theoretisch beantwordten, aber das willst du sicher nicht, deine Klasse muß laufen, oder?
Guude!
Fritz 8) 8)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

3ff, Ubuntu hat ein Paket für die Matplotlib, das kannst du einfach nachinstallieren, ist in den normalen Ubuntu-Repositories.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
3ff
User
Beiträge: 191
Registriert: Dienstag 22. Dezember 2009, 12:54
Wohnort: Odenwald Sued-Hessen

@Leonidas,
schon klar. Die Bibliothek, die Du vorgeschlagen hast, hab ich auch!
Schau mal auf die import-funktion matplotlib.pyplot.
Die gibts nicht!
ich wollte dem Kollegen nur helfen, aber irgendwie scheint mir die Geschichte schief eingestielt zu sein.
Die FFT hat nichts mit Quantenphysik und der Heisenbergschen Unschärferelation zu tun.
Wenn er sich nicht mehr meldet, sollten wir diesen Beitrag (neudeutsch Thread) vergessen, denn es führt zu nichts.
Obwohl die Klasse, die er konstruiert hat, macht Sinn, aber es fehlt halt Information.
Guude!
Fritz 8) 8)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

3ff hat geschrieben:schon klar. Die Bibliothek, die Du vorgeschlagen hast, hab ich auch!
Schau mal auf die import-funktion matplotlib.pyplot.
Die gibts nicht!
Die gibt es durchaus, habe ich gerade ausprobiert. Kann es sein, dass du eine Datei namens ``matplotlib.py`` hast, die die Library überdeckt?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Pretender2k
User
Beiträge: 27
Registriert: Freitag 23. Januar 2009, 18:23

hendrikS hat geschrieben:Bin leider nicht zu Hause und kann nur ein Codereading anbieten.
Wie Du weißt muß fa mindest doppelt so hoch wie fmax des Signals sein, um es sicher reproduzieren zu können. Ich denke, das ist bei Dir nicht gegeben.
Fa = 1
fmax = 6
Kann aus meiner Sicht nichts sinnvolles bei rauskommen.
Du erwartest ja sicher drei Linien als Spektrum. Siehst Du sie?
Hast Du schon eine IFFT gemacht? Wie sieht das Signal jetzt aus?
Laut dem Nyquist-Shannon-Abtasttheorem muss die Abtastfrequenz mindestens doppelt so gross sein wie die hoechste im Signalvorkommende Frequenz.

Meine Abtastzeit ist: T = (1/256) was einer Abtastferquenz fa = 256 Hz entspricht. Die Abtastfrequenz ist damit schonmal mehr als ausreichend da fmax = 6 Hz ist. Muesste also passen!

IFFT hab ich eben durchgefuehrt. Erhalte exakt die gleiche Funktion zurueck!
3ff hat geschrieben:@Leonidas,
schon klar. Die Bibliothek, die Du vorgeschlagen hast, hab ich auch!
Schau mal auf die import-funktion matplotlib.pyplot.
Die gibts nicht!
ich wollte dem Kollegen nur helfen, aber irgendwie scheint mir die Geschichte schief eingestielt zu sein.
Die FFT hat nichts mit Quantenphysik und der Heisenbergschen Unschärferelation zu tun.
Wenn er sich nicht mehr meldet, sollten wir diesen Beitrag (neudeutsch Thread) vergessen, denn es führt zu nichts.
Obwohl die Klasse, die er konstruiert hat, macht Sinn, aber es fehlt halt Information.
Guude!
Fritz 8) 8)
Alles oeffentlich zugaengliche Funktionen. Nix selbst geschrieben. Alle Funktionen die importiert werden, sollten mit den entsprechenden Bibs auch zu finden sein.

Das die FFT nix mit Quantenphysik zu tuen hat ist mir klar :) aber trotzdem exisitiert bei einer DFT (die FFT ist ja eine DFT) eine Unschaerfe-Relation.
Zuletzt geändert von Pretender2k am Dienstag 10. August 2010, 09:31, insgesamt 1-mal geändert.
Pretender2k
User
Beiträge: 27
Registriert: Freitag 23. Januar 2009, 18:23

Nachdem ich mir nochmal den Wikipedia Artikel gerade nochmal durchgelesen habe, scheint es mir so, dass die Frequenzaufloesung im Spektrum tatsaechlich nur ueber eine vergreosserung des Zeitfensters erfolgen kann. Meine Arbeit wird somit zwar deutlich erschwaert, aber anscheinend ist das Verhalten der FFT einfach so.

Sprich wenn ich das Zeitfenster zwei perioden gross mach, ist die Frequenzaufloesung kleiner als wenn ich das Zeitfenster vier perioden der Signalfrequenz gross mache. :K

Waere gut, falls mir das jemand bestaetigen koennte. Dann koennte man den thread naemlcih einfach schliessen. Da ja gar kein Problem mehr besteht bzw. gar keins bestand :shock:

Edit: Sorry wegen doppelpost
3ff
User
Beiträge: 191
Registriert: Dienstag 22. Dezember 2009, 12:54
Wohnort: Odenwald Sued-Hessen

@Leonidas,
Hurra, dieser Lappy hat tatsaechlich die o.a. Klasse mit der matplotlib.pyplot uebersetzt.
Ich entschuldige mich fuer die Aussage von Gestern.
Der andere Lappy, der diese Matplotlib nicht ¨fressen¨ wollte, ist allerdings randvoll und muesste/muss mal aufgeraeumt werden.
Mir kam der Aufruf von Python etwas komisch vor.
Guude!
Fritz :D
3ff
User
Beiträge: 191
Registriert: Dienstag 22. Dezember 2009, 12:54
Wohnort: Odenwald Sued-Hessen

@Pretender2k
alles klar,
hab Dein File als script laufen lassen, mein Lappz was erst im Wald, weil die FFT seeehr speicherintensiv ist, aber dann kam es.
Du muesstest die Fragen nochmal genauer formulieren. Bei mir sieht es eigentlich plausibel aus. Es handelt sich in dem einen Bild um eine modulierte Sinuskurve.
Wenn ich es noch aus meiner Studentenzeit heraus erinnere, willst du die Fourierkoefizienten der Summenfunktion wissen.
Damit kann man die Zeitfunktion in den Bildbereich transformieren.
Literatur gibts dazu genug.
Schau mal:
Mathematik fuer die Praxis von Kurt Schroeder
VEB Deutscher Verlag der Wissenschaften Berlin 1966
S. 174 ff.
Guude!
Fritz 8) 8)
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

Pretender2k hat geschrieben:Nachdem ich mir nochmal den Wikipedia Artikel gerade nochmal durchgelesen habe, scheint es mir so, dass die Frequenzaufloesung im Spektrum tatsaechlich nur ueber eine vergreosserung des Zeitfensters erfolgen kann. Meine Arbeit wird somit zwar deutlich erschwaert, aber anscheinend ist das Verhalten der FFT einfach so.

Sprich wenn ich das Zeitfenster zwei perioden gross mach, ist die Frequenzaufloesung kleiner als wenn ich das Zeitfenster vier perioden der Signalfrequenz gross mache. :K

Waere gut, falls mir das jemand bestaetigen koennte.
die Frequenzauflösung berechent sich folgendermassen:
Auflösung = Abtastrate / Anzahl der Werte

Entweder du erhöhst die Blocklänge (Anzahl der Werte) oder du verkleinerst die Abtastrate. Die Abtastrate verkleinerst du indem du das abgetastete Signal nocheinmal abtastest, da musst du dir sicher sein, dass du immernoch das Abtasttheorem einhälst (evtl noch einen Tiefpassfilter dazuschalten).
Ein Beispiel, du tastest mit 256Hz ab dann nimmst du von diesem Signal nur jeden 4. Wert und damit hast du die Abtastrate geviertelt und die Frequenzauflösung vervierfacht.
Benutzeravatar
hendrikS
User
Beiträge: 420
Registriert: Mittwoch 24. Dezember 2008, 22:44
Wohnort: Leipzig

Ich konnte den Code jetzt mal ausführen. Ist nichts ungewöhnlich wie ich erst angenommen hatte. Also ich war mir nicht ganz sicher was linspace exakt zurückgibt.
Die drei Linien kann mann auch gut erkennen.
Ich weiss leider nicht wo das Problem genau ist.

Und dann noch was zum Python code selbst. Also ich meine die Klasse drumherum ist Overkill. Javasmell. Wem's gefällt.
Pretender2k
User
Beiträge: 27
Registriert: Freitag 23. Januar 2009, 18:23

DaMutz hat geschrieben: die Frequenzauflösung berechent sich folgendermassen:
Auflösung = Abtastrate / Anzahl der Werte

Entweder du erhöhst die Blocklänge (Anzahl der Werte) oder du verkleinerst die Abtastrate. Die Abtastrate verkleinerst du indem du das abgetastete Signal nocheinmal abtastest, da musst du dir sicher sein, dass du immernoch das Abtasttheorem einhälst (evtl noch einen Tiefpassfilter dazuschalten).
Ein Beispiel, du tastest mit 256Hz ab dann nimmst du von diesem Signal nur jeden 4. Wert und damit hast du die Abtastrate geviertelt und die Frequenzauflösung vervierfacht.

Genau das war mein Problem. Machmal braucht man echt ein paar Anlaeufe ums endlich zu raffen :) Wie in meinem ersten Post geschrieben, hab ich das bereits schon in anderen Foren gefunden, dass die Frequenzaufloesung sich mit der Formel berechnen kann. Als ich aber rumexperimentiert habe, ist mir leider ein Fehler durch meinen Programmcode unterlaufe. Durch:

Code: Alles auswählen

# Time
self.time = linspace(0,5,2**8)
		
# Sampel Frequenz
self.dt = self.time[1]
self.fa = 1/self.dt
hab ich bisher immer die Anzahl der Werte festgelegt. Dummerweise hab ich ,wenn ich die Anzahl der Werte veraender hatte, auch automatisch die Abtastfrequenz veraendert. Das Resultat war, dass die Frequenzaufloesung immer gleich war!!!

Also hab ich etwas an der Groesse meines Zeitfensters rumgespielt( hier 5 sec.) und somit die Frequenzaufloesung erhoeht. Meine Folgerung, dass man die Frequenzaufloesung ueber die Groesse des Fensters bestimmt ist natuerlich bloedsinn, da ich durch die vergroesserung des Fensters automatisch die Abtastfrequenz verkleinert hatte. Naja jetzt hats ja zum glueck doch noch klick gemacht und es scheint, dass die FFT doch noch brauchbar werden koennte fuer mich :)

Die Stelle des Programmcodes schaut jetzt auch so aus:

Code: Alles auswählen

# Number of values and ampling rate
sefl.N = 256
self.fa = 48

self.time = (1./self.fa)*arange(0,self.N,1)
Danke an alle fuer das Feedback nochmal.

P.S.: Die Klasse ist vielleicht etwas ueberfluessig fuer das Beispiel. Aber beim Einbinden spaeter in ein Programm, ist ne Klasse dann doch sehr schoen und uebersichtlich :) Aber falls trotzdem etwas unueblich ist, was Bezeichnungen der Methoden oder der Variablen angeht, bin ich immer offen mcih da an den allgemeinen python style anzupassen :)
Antworten