I'm new in processing signals and need your help.
I have acquired a 10 seconds raw PPG (Photoplethysmogram) signal from my TI AFE4490. My hardware is calibrated and I'm using 250 samples per second to record those signal. I acquired 2500 points at the end.
You can see the image, the points and the code below.
Top: My raw PPG Signal - Bottom: Trying apply an FFT:

Code:
RED, IR, nSamples, sRate = getAFESignal()
period = 1/sRate
plt.figure(1)
plt.subplot(2,1,1)
x = np.linspace(0.0, nSamples*period, nSamples)
y = IR
plt.xlabel("Time (s)")
plt.ylabel("Voltage (V)")
plt.plot(x,y)
plt.subplot(2,1,2)
yf = fft(y)
xf = np.linspace(0.0, 1.0/(2.0*period), nSamples//2)
plt.xlabel("Frequency (Hz)")
plt.ylabel("Gain")
plt.plot(xf, 2.0/nSamples * np.abs(yf[0:nSamples//2]))
plt.grid()
plt.show()
The function getAFEsignal() is just a function to read a .txt file and put all into two numpy arrays.
Here you can find the .txt file: Raw signal file
As you can see, I didn't apply the FFT correctly, and I need this to discover which frequencies I need to filter. Do you know what I'm doing wrong, and if is possible to apply FFT on this signal?
The good news is that your computation of the FFT is fine. The data you show in the time domain has a fairly strong low frequency component. Correspondingly, your frequency-domain graph you get shows a significant spike near 0Hz.
The main problem lies in how you plot the results. To better see what you might expect to see in the frequency-domain based on an intuitive perception of the time-domain waveform you would need to readjust the scale of each axis. In particular, on the time scale shown you might expect to notice patterns with a duration of around 0.25 seconds up to maybe a few seconds. That would correspond to a frequency range of roughly 0-5Hz. It would then make sense to focus on that range instead of showing the entire 0-125Hz spectrum. This can be achieved by setting the x-axis limits as such:
plt.xlim(0,5) # set x-axis limits from 0 to 5Hz
Similarly for the y-axis, you need to consider that frequency components with small amplitudes (to the point of becoming harder to notice on a linear scale) can still have a very perceptible contribution on the time-domain signal. As such it is often desirable to show the frequency-domain amplitudes on a logarithmic decibel scale. This can be done as follows:
plt.plot(xf, 20*np.log10(2.0/nSamples * np.abs(yf[0:nSamples//2])))
Finally, if you want to better see the contribution of some specific frequency components without the interference from spectral leakage from other frequency component, you may want to consider pre-filtering your time-domain signal before computing the FFT. For example, if you want to eliminate the effect of the constant signal bias, the slow ~0.1Hz variation and the noises with frequency greater than 10Hz you might use something like the following:
import scipy.signal
b,a = signal.butter(4, [0.25/sRate, 10/sRate], btype='bandpass')
y = signal.filtfilt(b,a,signal.detrend(IR, type='constant'))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With