Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Perform FFT over a signal as if it was centered around zero #23478

Open
idokazma opened this issue Mar 28, 2023 · 2 comments
Open

ENH: Perform FFT over a signal as if it was centered around zero #23478

idokazma opened this issue Mar 28, 2023 · 2 comments

Comments

@idokazma
Copy link

idokazma commented Mar 28, 2023

Proposed new feature or change:

In the FFT algorithm, the first sample is considered to be at t=0.
This means that even that ALL the vectors that will go inside are asymmetric. Therefore, all the answers will be complex.

This is mathmatically true, but when you learn for example the FFT of a rect function (lets say, np.ones(N)), you "expect" to get a sinc function (which is Real only) but you get a complex answer. Again, this is because the FFT is done on signal that STARTS from zero, and is not symmetric around zero effectivly.

If you could insert a flag that can make you do an FFT as if the signal was symmetric around zero (t=-n/2 to t=n/2) and cancel this insertion of phase.

https://www.linkedin.com/posts/ido-kazma-596310174_signalprocessing-fft-numpy-activity-6922788016688103424-4PPe?utm_source=share&utm_medium=member_desktop

image
image

@idokazma idokazma changed the title ENH: Perform FFT over a signal as its center is zero ENH: Perform FFT over a signal as if its was centered around zero Mar 28, 2023
@idokazma idokazma changed the title ENH: Perform FFT over a signal as if its was centered around zero ENH: Perform FFT over a signal as if it was centered around zero Mar 28, 2023
@mhvk
Copy link
Contributor

mhvk commented Mar 28, 2023

The FFT is pretty strictly defined as starting at 0, but I can see the case for making it easier to have functions symmetric around 0. This is not all that different from wanting spectra with the middle instead of the start at 0, which one can do with np.fft.fftshift. Similarly, for the input data, one option is to use np.fft.ifftshift:

# Create rect
a = np.zeros(33)
a[14:19] = 1
ft = np.fft.fft(np.fft.ifftshift(a))
np.isclose(ft.imag, 0).all()
# True

Rather than have a new argument, maybe the easiest would be to explicitly mention the use of np.fft.ifftshift in the np.fft.fft (and np.fft.rfft) docstrings and the more general documentation?

@idokazma
Copy link
Author

idokazma commented Mar 29, 2023

Your example is a nice one but:

  1. It requires you to pad your signal from both sides with zeros. (if my input was sig=np.ones(5) I would have needed to transform it to a [0,0,0,... 1,1,1,0,0,..0]. I find it quite ugly.
  2. It works only on odd length vectors. If my signal was 'sig=np.ones(4)' it would not work.
  3. Its output is an oversampled fft (in your case, with length of 33) when all I wanted is an FFT with length of 4. You'll need to downsample it...

What I suggest is like this:

import numpy as np
import plotly.graph_objects as go

a = np.ones(10)
fft_len = 128

ft = np.fft.fft(a,n=fft_len)
# before
go.Figure([go.Scatter(y=np.real(ft)), go.Scatter(y=np.imag(ft))])

image

# after
phase_corr = np.exp(1j*2*np.pi*np.linspace(0,1,len(ft), endpoint=False)*(len(a)-1)/2)
ft_corr = ft*phase_corr
go.Figure([go.Scatter(y=np.real(ft_corr)), go.Scatter(y=np.imag(ft_corr))])

image

This will work for any len(a) and any fft_len.
Pay attention that for sig=np.ones(N), the natural fft (np.fft.fft(sig)) gives zero imag part, not because it's naturally zero, but because it is sampled in points where fft(sig)=0 (specificlly for this sig).

Try another symmetric function and see. For example:

a = np.ones(10)
a[2:-2] = 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants