I'm using numpy.fft in python to compute Fast Fourier Transforms. In particular, I'm using rfft as I have a real signal and don't need negative frequencies.
My question is: my signal has 184320 points currently and encompasses multiple periods. Should I be truncating the signal after a certain number of periods for best results? I know the sample rate in which the data was collected. What's sparking this question is that applying various windows is changing the amplitudes at each frequency of interest quite significantly, and I'm wondering if perhaps I should be truncating my signal.
- 8,912
- 5
- 23
- 74
- 11
- 4
-
what's the sampling rate? – Jdip Aug 16 '22 at 19:10
-
@Jdip, my sampling rate is 15360 Hz – Bern Aug 16 '22 at 19:26
-
Read my edited answer. If you still have trouble, you can post the frequencies you’re trying to get an amplitude for and I’ll help you out further ;) – Jdip Aug 16 '22 at 19:31
-
Looking to compare my results so the frequencies I'm interested in are from 60 - 2940 (in increment steps of 60) – Bern Aug 16 '22 at 19:55
-
Ok so you need frequency bins $k=f_n \cdot nfft/15360$ at $f_n = n \cdot 60$ so $nfft = 256$ is the smallest chunk of your data you can use (assuming your signal is stationary, I.e the frequencies don’t change over time). You can also just use 15360 samples chunk, I.e 1s of your data, giving you exactly 1hz per bin – Jdip Aug 16 '22 at 20:10
-
Above, to be consistent with my answer (which you can accept if happy with, thanks!), $dF = 60$ so $Nfft = f_s/dF = 256$ – Jdip Aug 16 '22 at 20:22
-
Are you trying to determine the Fourier coefficients for a function known to be periodic using the DFT? – robert bristow-johnson Aug 16 '22 at 22:30
-
@robertbristow-johnson, yes – Bern Aug 17 '22 at 18:07
-
Do you know the fundamental frequency $f_0$ of the periodic signal or is that unknown? – robert bristow-johnson Aug 17 '22 at 18:57
3 Answers
Title: no such thing. The DFT (which is what FFT computes) doesn't require anything beyond the input being finite in length and values.
Body: keep truncating until the FFT is perfect impulses (just peaks, no leaky stuff). To the DFT, the input is a perfect sine if there's an integer number of cycles of it. Note however, truncation will change the peak's location, and its value, which need accounting for: frequency normalization for former, amplitude for latter via *= N_orig / N_trunc (for pure sines only). If the signal is measured rather than synthetically generated, then you'll most likely never get a perfect impulse.
If the goal is reliable amplitude estimation, FFT is a suboptimal tool; I recommend time-frequency analysis (CWT, STFT), which also don't suffer from the 'measured' problem. Details here under "Modulation Model vs Fourier Transform".
- 8,912
- 5
- 23
- 74
-
//"The DFT (which is what FFT computes) doesn't require anything beyond the input being finite in length and values.// --- That's true, but because of the nature of the basis functions of the DFT, certain properties are inherent. – robert bristow-johnson Aug 16 '22 at 22:43
Choose an appropriate FFT length (for your signal, such as 2^18), and scale your FFT result by $1/sum(\texttt{window})$ (for no window, that would be $1/N$ with $N$ your input signal length).
EDIT That's if you are set on using the FFT as an amplitude estimation tool. As pointed out by @OverLordGoldDragon, there are better tools for that.
EDIT: Updated answer with frequency precision and padding explained
Each frequency bin $k$ has center frequency $f_{k_{(\texttt{Hz})}} = kdF_{(\texttt{Hz})}$, with $dF_{(\texttt{Hz})} = f_s/\texttt{Nfft}$ the spectral precision, $\texttt{Nfft}$ the length of the DFT, i.e the length of your input sequence (padded or not), and $f_s$ the sampling frequency.
Here's an example: let $x(t)$ be a $0.5s$ long ($\texttt{Nfft} = 22050$) signal sampled at $44100 \texttt{Hz}$. Its DFT, $X[k]$, has precision $dF = 2 \texttt{Hz}$ with no padding. That means that component at $2000 \texttt{Hz}$ would exactly fall at bin $k = f / dF = f \cdot \texttt{Nfft}/f_s = 2000 \cdot 22050 / 44100 = 1000$
But a component at $2001 \texttt{Hz}$ would fall between bins 1000 and 1001 (because $f/dF = 1000.5$ so the fft output will spread between bins $1000$ and $1001$).
By padding your signal to twice its original length, you can double the signal length $\texttt{Nfft}$, effectively doubling the frequency precision $dF$ to $1\texttt{Hz}$, and a $2000 \texttt{Hz}$ component now falls at the center of bin $k = f \cdot \texttt{Nfft} /f_s = 2000 \cdot 44100 / 44100 = 2000$ and a component at $2001\texttt{Hz}$ falls at the center of bin $2001$ by the same calculations.
All this to say, if you know the frequencies of interest, you can deduce the exact frequency precision $dF$ you need, from there you can deduce the input length you need by doing $\texttt{Nfft} = f_s/dF$ and use that to guide how much padding/truncating you need to apply.
- 5,980
- 3
- 7
- 29
-
Thanks for the insight. I'm working on a project with the requirement that it be done using FFT. In the future I'll definitely check out the tools proposed. The signal that I'm dealing with can be considered as a bunch of sine waves added together (with a slight phase) so that the resulting waveform isn't a perfect sine wave. I read online that numpy fft doesn't require it to be an integer power of 2. Would you recommend padding with zeros to make it 2^18 length? – Bern Aug 16 '22 at 17:55
-
You don’t need to pad, no. You might want to pad however to get better frequency precision, which in your case might be useful to get exact amplitude measurements. The power of 2 length requirement is only for efficiency, so unless you’re worried about that, no need. – Jdip Aug 16 '22 at 17:57
-
good to know. That isn't much of a concern but I'll keep it in the back of my mind for the future. Going back to the idea of truncating the signal, do you have any more guidance on how to properly do that? I'm currently unsure on what point to do so, which of course is changing quite significantly the output amplitudes. – Bern Aug 16 '22 at 18:03
-
Why do you want to truncate your signal? And it shouldn’t change the signal amplitude if you make sure to scale your result like I mentioned… – Jdip Aug 16 '22 at 18:04
-
I'm attempting to window the my spectrum to get "cleaner" results. One of the things I'm noticing is that the application of windows changes the output amplitudes at frequencies of interest, quite significantly. It was recommended to me to try looking at only a chunk of my signal to see if that helps at all. I'm pretty new to this stuff so figured I'd give it a shot, but if you have any suggestions for windowing, I'd be grateful for those too! – Bern Aug 16 '22 at 18:07
-
Could you explain a bit further by what 1/sum means? I understand the 1 / N which is what I'm using for the non-windowed output, but am not sure what sum I should be tracking? – Bern Aug 16 '22 at 18:10
-
My suggestion is either to NOT window your signal (equivalent to a rectangular window), or use a hamming or hann window, but the output amplitudes should not change from window to window IF you scale the results by 1/sum(window). The amplitude can change with different chunks because the frequencies of interest will be spread across different frequency bins, so I also suggest padding your signal to make sure each frequency of interest falls in the center of their corresponding frequency bin. – Jdip Aug 16 '22 at 18:12
-
No windowing is equivalent to multiplying your signal by a rectangular window, i.e the associated sequence [1 1 1 1 1 .. ] with same length as your signal, so in that case sum(window) = 1+1+1+... = N that's why you scale by 1/N. For a hann window you want to sum the associated hann sequence and scale by 1/sum(hann) – Jdip Aug 16 '22 at 18:15
-
I'll give both windows you recommended a shot and will get to the point where the amplitudes remain the same. Two follow-ups, can you explain what you mean by sum(window) - I'm not sure what exactly I'm to be tracking (just saw your comment so ignore that question!). Second, do you know what the easiest method is to pad the signal so that the frequency of interest is in the center? Or do I need to just do guess and check? – Bern Aug 16 '22 at 18:16
-
Number of periods of signal required when doing an FFT: $1$
- 20,661
- 4
- 38
- 76
-
1Of course Robert's answer is as right and short as it could ever be. To add to my previous comments, in your case, your lowest frequency of interest being 60Hz, at a sampling rate $f_s = 15360$, a full period would be 1/60 = 0.0167s, which is exactly 256 samples. – Jdip Aug 16 '22 at 22:26
-
1yup. never said anything about sample rate. just something about the inherent nature of the DFT. – robert bristow-johnson Aug 16 '22 at 22:36
-
"Lengths of sides required to make a rectangle must sum to its perimeter". – OverLordGoldDragon Aug 16 '22 at 22:57
-
1