I'm trying to find the set of fft2 sinusoids that sum up to my original 2d data (entirely real numbers). I found this example, doing the same thing for fft, incredibly helpful (thanks @mark snyder).
I noticed that if I drop the 2nd dimension, then my first column always matches, which tells me I'm not too far off? Finally, why did I have to subtract 1 from input into dimT to align the phase?
Here's what I've tried:
import pandas as pd
import numpy as np
from scipy.fftpack import fftfreq, fft2
import cmath
df=pd.DataFrame( { 'Ang':[ 0.091, -0.141, -0.114],
'Con':[ -0.139, -0.259, -0.573],
'EAC':[ 0.016, -0.106, -0.044] } ,
columns=['Ang', 'Con', 'EAC'] ,
index=[2011,2012,2013] )
my_fft = fft2(df)
T , B =len(df) , len(df.columns)
freqsT , freqsB = fftfreq(T,1) , fftfreq(B,1)
def ifft2Manually(option):
recombine = np.zeros((T,B)) #recombineine
for t in list(range(T)):
for b in list(range(B)):
coef = abs(my_fft[t][b])/(T*B)
tfreq , bfreq = freqsT[t] , freqsB[b]
ps = cmath.phase(my_fft[t][b])
dimT = coef*np.cos(tfreq*2*np.pi*( np.array([df.index]).T - 1 ) + ps )
dimB = coef*np.cos(bfreq*2*np.pi*( np.array(list(range(B))) ) + ps )
if option==1:
sinusoid = dimT + dimB
else:
sinusoid= dimT #exclude dimB here
recombine=sinusoid +recombine
#print('\nt={}\nb={}\ndimT={}\ndimB={}\nsinusoid={}'.format(t,b,dimT,dimB,sinusoid))
if option==1:
print('\n nothing matches when both dimensions used')
else:
print('\n first column matches when ONLY the first dimension (dimT) is used')
print('\n original data:\n{} \n\n my attempt to match:\n{}'.format(df, recombine ))
ifft2Manually(option=1)
ifft2Manually(option=2)
********************** UPDATE: ********************************
This code below now seems to work. My main mistake was that the addition needed to happen inside of the cos() function instead of adding two cos() terms. Hopefully this small working example will help someone else in a similar situation.
import pandas as pd
import numpy as np
from scipy.fftpack import fftfreq, fft2
import cmath
row=2 # arbitrary
col=3 # arbitrary
df=pd.DataFrame( { 'A':[ 0.09, -0.12, -0.11],
'B':[ -0.13, 0.29, -0.57],
'C':[ 0.01, -0.16, -0.04],
'D':[ 0.10, 0.65, 0.46] } ,
columns=['A', 'B', 'C','D'] ,
index=[2011,2012,2013] )
print('here is the df:\n', df)
actual = np.array(df)[row][col]
my_fft2 = fft2(df)
T , B =df.shape[0] , df.shape[1]
mysum= 0
for t in range(T):
for b in range(B):
coef = abs(my_fft2[t][b])/(T*B)
bfreq , tfreq = fftfreq(B,1)[b] , fftfreq(T,1)[t]
ps = cmath.phase(my_fft2[t][b])
mysum += coef*np.cos( 2*np.pi*(tfreq*row + bfreq*col) + ps )
print('\n replicate value at row={}, col={}'.format( row, col))
print('\n yhat :', mysum)
print(' actual :' , actual )