I saw someone do this in a presentation but I'm having a hard time reproducing what he was able to do. Here's a slide from his presentation:
Pretty cool. He decomposed a dataset using FFT, then plotted the appropriate sine waves that the FFT specified.
So in an effort to recreate what he did, I created a series of points that correspond to the combination of 2 sine waves:
import matplotlib.pyplot as plt
import numpy as np
%matplotlib inline
x = np.arange(0, 10, 0.01)
x2 = np.arange(0, 20, 0.02)
sin1 = np.sin(x)
sin2 = np.sin(x2)
x2 /= 2
sin3 = sin1 + sin2
plt.plot(x, sin3)
plt.show()
Now I want to decompose this wave (or rather, the wave that the points imply) back into the original 2 sine waves:
# goal: sin3 -> sin1, sin2
# sin3
array([ 0.00000000e+00, 2.99985000e-02, ... 3.68998236e-01])
# sin1
array([ 0. , 0.00999983, 0.01999867, ... -0.53560333])
# sin2
array([ 0. , 0.01999867, 0.03998933, ... 0.90460157])
I start by importing numpy
and getting the fft
of sin3
:
import numpy as np
fft3 = np.fft.fft(sin3)
ok, that's about as far as I get. Now I've got an array with complex numbers:
array([ 2.13316069e+02+0.00000000e+00j, 3.36520138e+02+4.05677438e+01j,...])
and if I naively plot it I see:
plt.plot(fft3)
plt.show()
Ok, not sure what to do with that.
I want to get from here to the datasets that look like sin1 and sin2:
plt.plot(sin1)
plt.show()
plt.plot(sin2)
plt.show()
I understand the real and imaginary part of the complex numbers in the fft3
dataset, I'm just not sure what to do with them to derive sin1
and sin2
datasets from it.
I know this has less to do with programming and more to do with math, but could anyone give me a hint here?
EDIT: update on Mark Snyder's answer:
Using Mark's code I was able to get what I expected and ended up with this method:
def decompose_fft(data: list, threshold: float = 0.0):
fft3 = np.fft.fft(data)
x = np.arange(0, 10, 10 / len(data))
freqs = np.fft.fftfreq(len(x), .01)
recomb = np.zeros((len(x),))
for i in range(len(fft3)):
if abs(fft3[i]) / len(x) > threshold:
sinewave = (
1
/ len(x)
* (
fft3[i].real
* np.cos(freqs[i] * 2 * np.pi * x)
- fft3[i].imag
* np.sin(freqs[i] * 2 * np.pi * x)))
recomb += sinewave
plt.plot(x, sinewave)
plt.show()
plt.plot(x, recomb, x, data)
plt.show()
later I'll make it return the recombined list of waves, but for now I'm getting an anomalie I don't quite understand. First of all I call it like this, simply passing in a dataset.
decompose_fft(sin3, threshold=0.0)
But looks great but I get this weird line at y=0.2
Does anyone know what this could be or what's causing it?
EDIT:
The above question has been answered by Mark in the comments, thanks!