Test FFT mit Sinus-Funktion

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Hallo Ihr Lieben,

um meine FFT besser zu verstehen teste ich die Funktion gerade mit folgendem Code:

Code: Alles auswählen

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from scipy import fft

x = np.linspace(0,2*np.pi,100)
y = np.sin(x)

X = fft.rfftfreq(x.size,1/100)
Y = np.abs(fft.rfft(y))

fig, ax = plt.subplots()

ax.plot(X,Y)
ax.set_xlim(0,2*np.pi)
Ich erzeuge einen Sinus der eine Frequenz von 1Hz haben soll. Abtastfrequenz ist 100Hz mit 100 Punkten.
Soweit so gut, der Peak der FFT liegt bei 1 Hz.
Was sagt mir aber die Amplitude der FFT? Die liegt bei ~50 obwohl der Sinus eine Amplitude von 1 hat.

Bild
Bild
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da fehlt die Normalisierung. Erklärt zB hier: https://www.mathworks.com/matlabcentral ... ncy-domain - du musst durch 100 teilen & mal 2 nehmen.
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Durch 100 teilen weil ich 100 bins habe und mal 2 weil die fft die Intensität auf positive wie negative frequenzen aufteilt - ist das korrekt so?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Genau. Ich habe nicht verifiziert, dass du die einseitige FFT benutzt, aber dein Graph sieht zumindest danach aus.
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Um zum Thema Auswertung einer FFT, gibt es da etwas mit dem ich die verschiedenen Peaks finden kann? Stelle mir das recht komplex vor, wenn ich das selbst schreiben müsste

Das Ergebnis sollte ungefähr so aussehen:

Peak 1 bei X Hz mit Y Amplitude
Peak 2 bei X Hz mit Y Amplitude
Peak 3 bei X Hz mit Y Amplitude
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Peak detection kann man auch suchen und findet da sicher was. Im konkreten fall bei so wenigen diskreten Werten ist das aber ja trivial. Höchsten wert bestimmen, entfernen & wieder von vorne beginnen.
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

@__deets__ bist du dir sicher mit dem Faktor 2?

Ich habe zwei Proben gemacht mit zwei bekannten Datensätzen und einmal funktioniert es mit der 2 und einmal nicht.

Code: Alles auswählen

%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
from scipy.fft import rfft, rfftfreq
from scipy.signal import find_peaks

A=1
f=1
tmax=1
samples=1000
#t = np.array(df0["t"])
#y = np.array(df0["z"])

t = np.linspace(0,tmax,samples, endpoint=False)
y = A*np.sin(2*np.pi*f*t) 

T = rfftfreq(t.size,tmax/samples)
Y = np.abs(rfft(y, norm="forward"))

fig, axs = plt.subplots(1,2, figsize=(12*1.6,6))


axs[0].scatter(t,y)
axs[0].set_xlim(0,tmax)

axs[1].plot(T,Y)
axs[1].set_xlim(-2,10)

Bild
Bild

Wo liegt der hund begraben?
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wo kommt denn das 2te Signal her? Ich sehe da keine Frequenz etc. Vor allem aber hat das einen Gleichspannungsanteil, das ist der Wert an 0. Wenn du den ignorierst (der kann groß werden), was ergibt sich dann?
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Das zweite Signal ist die gemessene konstante Erdbeschleunigung in g mit einem Beschleunigungssensor. Also konstant ca. |1|, die FFT müsste dann ja bei 0Hz auch ~1 liefern, was sie auch macht, allerdings nur ohne den Faktor 2 und dann stimmts bei dem Sinus nicht mehr ( siehe Code )
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das wird dann schon am Geichspannungsanteil liegen, den musst du anders behandeln. Der ist einfach das Mittel des Signals. Manche bestimmen den auch vorher getrennt & subtrahieren ihn vom Signal, um nur auf die Frequenzen zu schauen. Da sollte dann der Noise deines Sensors erscheinen.
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Breaking down confusions over fast fourier transform fft:
https://medium.com/analytics-vidhya/bre ... 61a029b1ab

How to remove DC part of fft:
http://blog.originlab.com/how-to-remove ... orming-fft
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

@__deets__

Meine Python FFT dient mir nun als eine Referenz-FFT ( siehe blau ) für meine eigentliche FFT auf einem Mikrocontroller ( siehe rot ).
Es fällt auf, dass die FFT im µC ( siehe in rot ) mit ziemlich genau 2.384E-07 skaliert und nicht mit 2/N - wie kann dieser merkwürdige Faktor plausibel erklärt werden?

Das hier ist die FFT ( Cooley-Tukey ) die ich auf dem µC nutze: https://github.com/brendanashworth/fft-small

Bild
Bild
__deets__
User
Beiträge: 14539
Registriert: Mittwoch 14. Oktober 2015, 14:29

Auf Anhieb erstmal nicht. Ich wuerde da mit rumspielen, im Zweifel auch mal dadurch, den Code auf deinem PC zum laufen zu bringen (unter Linux/macOS zumindest ist das trivial) und mal verschiedene FFTs durchzurechnen, ob es da ein Muster gibt, ob es ggf. an den MCU floating point Funktionen liegt, so Dinge.
jp21
User
Beiträge: 20
Registriert: Freitag 1. April 2022, 14:33

Die Lösung war:

Ich übergebe in C die rohdaten als int16_t die so direkt vom Sensor kommen. Ich muss das noch normieren mit (RANGE / 32768) damit physikalisch sinnvolle Werte rauskommen :-)
Antworten