I am trying to evaluate the frequency domain of several signals. For this I used the PSD implementation given in this answer. As a comparison I used the signal.periodogram function provided in scipy:
from scipy.signal import tukey
import scipy as sp
f, Pxx_den = sp.signal.periodogram(a_gtrend_orig,12,window=tukey( len(a_gtrend_orig) ))
However when I plot this next to the self-implemented PSD they look significantly different:
As the same window function is used and the periodogram function should also use an FFT where does this difference coming from?
The example that you are comparing this to, is graphing the amplitude at each frequency bin, i.e, abs(fft())
The periodogram produces a power spectral density, that means it is the square of the amplitude at each frequency bin.
The label "windowed psd" is from an early edit, and was corrected later.
Related
If I do the FFT of the "usual" rectangular pulse function I get this "weird" result:
However, If I roll the same signal by half (f = np.roll(f, f.size//2)) and calculate the FFT, I get what I was expecting if I had used the non-rolled signal, i.e., get the sinc function as result:
By the way, if I do what most people do, i.e., if I plot the magnitude of the spectrum (instead of just the real part) of either signal (usual or rolled) I'll get exactly the same result (that resembles closer to the sinc).
I was expecting to get the sinc function from the real part of the FFT of the "usual" rectangular function.
Does anybody know why do I need to roll the rectangular function in order to produce the sinc function?
I'm using scipy's fft.
Thanks
This is simply the shift property of the FFT (and IFFT). If you circularly shift the data in one domain, it's the same as multiplying by a complex sinusoid in the other domain, with the frequency of that modulation proportional to the amount of the shift.
Works the same way for shifts in either the time domain or frequency domain, causing modulation in the other domain.
For "unshifted" results, the 0 point (or circular symmetry center for strictly real FFT results) usually needs to be at the first element of the FFT or IFFT input vector, not the middle.
See: https://www.dsprelated.com/freebooks/mdft/Shift_Theorem.html
I tried to reproduce Watson's spectrum plot from these set of slides (PDF p. 30, p.29 of the slides), that came from this data of housing building permits.
Watson achieves a very smooth spectrum curve in which it is very easy to tell the peak frequencies.
When I tried to run a FFT on the data, I get a really noisy spectrum curve and I wonder if there is an intermediate step that I am missing.
I ran the fourier analysis on python, using scipy package fftpack as follows:
from scipy import fftpack
fs = 1 / 12 # monthly
N = data.shape[0]
spectrum = fftpack.fft(data.PERMITNSA.values)
freqs = fftpack.fftfreq(len(spectrum)) #* fs
plt.plot(freqs[:N//2], 20 * np.log10(np.abs(spectrum[:N//2])))
Could anyone help me with the missing link?
The original data is:
Below is the Watson's spectrum curve, the one I tried to reproduce:
And these are my results:
The posted curve doesn't look realistic. But there are many methods to get a smooth result with a similar amount of "curviness", using various kinds of resampling and/or plot interpolation.
One method I like is to chop the data into segments (windows, possibly overlapped) roughly 4X longer than the maximum number of "bumps" you want to see, maybe a bit longer. Then window each segment before using a much longer (size of about the resolution of the final plot you want) zero-padded FFT. Then average the results of the multiple FFTs of the multiple windowed segments. This works because a zero-padded FFT is (almost) equivalent to a highest-quality Sinc interpolating low-pass filter.
I'm completely new to python, scipy, matplotlib and programming in general.
I'm using the following code, which I came across online, to apply FFT to .wav files:
import scipy.io.wavfile as wavfile
import scipy
import scipy.fftpack as fftpk
import numpy as np
from matplotlib import pyplot as plt
s_rate, signal = wavfile.read("file.wav")
FFT = abs(scipy.fft.fft(signal))
freqs = fftpk.fftfreq(len(FFT), (1.0/s_rate))
plt.plot(freqs[range(len(FFT)//2)], FFT[range(len(FFT)//2)])
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.show()
The resulting graphs give amplitude values that range from 0 to a few thousands, depending on the files, and I have no idea what unit these are in. I'm guessing they might be relative amplitudes, and I was wondering if there is a way to turn that into decibels, as I need specific values.
Thank you
Tanguy
They are amplitudes relative to the quantization units used for the samples in your input signal. So, without calibrating your input signal against a known level of source input (to get Volts per 1 bit change, etc.), the actual units are unknown. If calibrated, you may still need to divide the magnitudes of the FFT output by N (the FFT length), depending on your particular FFT implementation.
To get Decibels, convert by taking 20*log10(abs(...)) of the FFT results, and offset by your 0 dB calibration level.
I have this signal, for which I want to calculate the dominant wavelength, which would be the distance between the pronounced minima where the oscillations occure:
Which tool in scipy should I look into for this mission?
It depends where you get the data from.
If you only have the (x,y) points of the graph, you can either hack it by taking all the x corresponding to the minimal y (be careful of floating-point equalities, though), or use the Fourier transform, identify the main wave (the biggest amplitude) and deduce its wavelength. For the latter, you would use the Fast Fourier Transform from scipy: https://docs.scipy.org/doc/scipy-0.18.1/reference/tutorial/fftpack.html#fast-fourier-transforms
If you have the functional description of the function, either sample it like you do to construct the graph and apply the above, or take its derivative to find the minima mathematically (best method). You could also use scipy to find the minima numerically (https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.optimize.minimize.html), but you have to manually specify intervals that contain only one local minimum.
I have a morlet wavelet which is described by a plane wave multiplied with a gaussian window, and a scaling parameter, s. I.e. in python language:
import numpy
f = 10
omega = 2*numpy.pi*f
x = numpy.linspace(-5,5,num=1000)
wavelet = numpy.exp(numpy.complex(0,1)*omega*x/s) * numpy.exp(-1.0*(x/s)**2/2.0)
Usually doubling the scaling parameter (also known as "level") of a wavelet halves its bandwidth. Plotting the FFT of the wavelet described above for different scales, s = 2**i, with i=1,2,3, ... the width is not halved for subsequent i.
Whats wrong with the morlet wavelet?
The above code that you have provided does not look (to me) as if it is properly constructing the Morlet wavelet. The paper A Practical Guide to
Wavelet Analysis provides a great guide to the construction of Wavelet transforms and should provide an explanation to the effect of varying the wavelet scale.
Note, depending on your implementation, changing the wavelet scale will not update/change the scale of the FFT used to create the wavelet. Typically, the FFT is constructed, then it is used to construct the Descreet Wavelet Transform. Thus, changing the wavelet scale will not effect the underlying FFT.
I hope this helps.