XYZT
XYZT

Reputation: 674

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?

Upvotes: 4

Views: 1324

Answers (1)

SleuthEye
SleuthEye

Reputation: 14579

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])

Upvotes: 8

Related Questions