Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why isn't this even function's FFT real?

So, in iPython, I run the following,

In [1]: from pylab import *;

In [2]: x = np.array([4.,3.,2.,1.,0.,1.,2.,3.,4.]);

In [3]: rfft(x)
Out[3]:
array([ 20.00000000+0.j        ,   7.79085937+2.83564091j,
        -0.21688142-0.18198512j,   0.50000000+0.8660254j ,
        -0.07397795-0.41954982j])

The variable x is an even function around the middle element in the array, but yet it's fft isn't entirely real as it should be. Why is that? How do I input an even function to numpy/scipy's fft function so it'll interpret it as the even function it's meant to be?

like image 272
XYZT Avatar asked Mar 13 '23 06:03

XYZT


1 Answers

The N samples cover a period of the signal without repeating samples (ie. without including the (N+1)st sample which is the same as the first one). To visualize this, you can match the samples with the corresponding symmetry candidate to get:

given signal        :              4 3 2 1 0 1 2 3 4
periodic extension  : ...  1 2 3 4 4 3 2 1 0 1 2 3 4 4 3 2 1 0 1 2 3 4 ...
symmetry            :              ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
                                   | | | | |_| | | | |
                                   | | | |_____| | | |
                                   | | |_________| | |
                                   | |_____________| |
                                   |_________________|

You can also verify this by plotting your signal with:

plt.plot(np.arange(18), np.append(x, x));
plt.plot(np.array([ 4.5, 4.5]), np.array([0,5]), 'r--');
plt.plot(np.array([ 9.0, 9.0]), np.array([0,5]), 'k--');
plt.plot(np.array([13.5,13.5]), np.array([0,5]), 'r--');
plt.axis([0, 18, 0, 5]);
plt.grid(True);
plt.show();

enter image description here

Where the dashed black line represent the period of your signal, and the red lines the midpoint along the period. As you can see, the signal is in fact not symmetric.

So according to that convention of not repeating the first sample, to get a symmetric signal you should define your signal as:

x = np.array([4.,3.,2.,1.,0.,1.,2.,3.])

which would produce the following real-valued (within numerical precision) frequency-domain sequence with the application of rfft:

array([ 16.00000000 +0.00000000e+00j,   6.82842712 -1.11022302e-15j,
         0.00000000 -0.00000000e+00j,   1.17157288 -1.11022302e-15j,
         0.00000000 +0.00000000e+00j])
like image 140
SleuthEye Avatar answered Mar 19 '23 14:03

SleuthEye