FFT real/imaginary/abs parts interpretation - numpy

I'm currently learning about discret Fourier transform and I'm playing with numpy to understand it better.
I tried to plot a "sin x sin x sin" signal and obtained a clean FFT with 4 non-zero points. I naively told myself : "well, if I plot a "sin + sin + sin + sin" signal with these amplitudes and frequencies, I should obtain the same "sin x sin x sin" signal, right?
Well... not exactly
(First is "x" signal, second is "+" signal)
Both share the same amplitudes/frequencies, but are not the same signals, even if I can see they have some similarities.
Ok, since I only plotted absolute values of FFT, I guess I lost some informations.
Then I plotted real part, imaginary part and absolute values for both signals :
Now, I'm confused. What do I do with all this? I read about DFT from a mathematical point of view. I understand that complex values come from the unit circle. I even had to learn about Hilbert space to understand how it works (and it was painful!...and I only scratched the surface). I only wish to understand if these real/imaginary plots have any concrete meaning outside mathematical world:
abs(fft) : frequencies + amplitudes
real(fft) : ?
imaginary(fft) : ?
code :
import numpy as np
import matplotlib.pyplot as plt
N = 512 # Sample count
fs = 128 # Sampling rate
st = 1.0 / fs # Sample time
t = np.arange(N) * st # Time vector
signal1 = \
1 *np.cos(2*np.pi * t) *\
2 *np.cos(2*np.pi * 4*t) *\
0.5 *np.cos(2*np.pi * 0.5*t)
signal2 = \
0.25*np.sin(2*np.pi * 2.5*t) +\
0.25*np.sin(2*np.pi * 3.5*t) +\
0.25*np.sin(2*np.pi * 4.5*t) +\
0.25*np.sin(2*np.pi * 5.5*t)
_, axes = plt.subplots(4, 2)
# Plot signal
axes[0][0].set_title("Signal 1 (multiply)")
axes[0][0].grid()
axes[0][0].plot(t, signal1, 'b-')
axes[0][1].set_title("Signal 2 (add)")
axes[0][1].grid()
axes[0][1].plot(t, signal2, 'r-')
# FFT + bins + normalization
bins = np.fft.fftfreq(N, st)
fft = [i / (N/2) for i in np.fft.fft(signal1)]
fft2 = [i / (N/2) for i in np.fft.fft(signal2)]
# Plot real
axes[1][0].set_title("FFT 1 (real)")
axes[1][0].grid()
axes[1][0].plot(bins[:N/2], np.real(fft[:N/2]), 'b-')
axes[1][1].set_title("FFT 2 (real)")
axes[1][1].grid()
axes[1][1].plot(bins[:N/2], np.real(fft2[:N/2]), 'r-')
# Plot imaginary
axes[2][0].set_title("FFT 1 (imaginary)")
axes[2][0].grid()
axes[2][0].plot(bins[:N/2], np.imag(fft[:N/2]), 'b-')
axes[2][1].set_title("FFT 2 (imaginary)")
axes[2][1].grid()
axes[2][1].plot(bins[:N/2], np.imag(fft2[:N/2]), 'r-')
# Plot abs
axes[3][0].set_title("FFT 1 (abs)")
axes[3][0].grid()
axes[3][0].plot(bins[:N/2], np.abs(fft[:N/2]), 'b-')
axes[3][1].set_title("FFT 2 (abs)")
axes[3][1].grid()
axes[3][1].plot(bins[:N/2], np.abs(fft2[:N/2]), 'r-')
plt.show()

For each frequency bin, the magnitude sqrt(re^2 + im^2) tells you the amplitude of the component at the corresponding frequency. The phase atan2(im, re) tells you the relative phase of that component. The real and imaginary parts, on their own, are not particularly useful, unless you are interested in symmetry properties around the data window's center (even vs. odd).

With respect to some reference point, say the center of a fixed time window, a sine wave and a cosine wave of the same frequency will look different (have different starting phases with respect to any fixed time reference point). They will also be mathematically orthogonal over any integer periodic width, so can represent independent basis vector components of a transform.
The real portion of an FFT result is how much each frequency component resembles a cosine wave, the imaginary component, how much each component resembles a sine wave. Various ratios of sine and cosine components together allow one to construct a sinusoid of any arbitrary or desired phase, thus allowing the FFT result to be complete.
Magnitude alone can't tell the difference between a sine and cosine wave. An IFFT(imag(FFT)) would screw up the reconstruction of any signal with a different phase than pure cosines. Same with IFFT(re(FFT)) and pure sine waves (with respect to the FFT aperture window).

You can convert the signal 1, which consists of a product of three cos functions to a sum of four cos functions. This makes the difference to function 2 which is a sum of four sine functions.
A cos function is an even function cos(-x) == cos(x).
The Fourier Transformation of an even function is pure real.
That is the reason why the plot of the imaginary part of the fft of function 1 contains only values close to zero (1e-15).
A sine function is an odd function sin(-x) == -sin(x).
The Fourier Transformation of an odd function is pure imaginary.
That is the reason why the plot of the real part of the fft of function 2 contains only values close to zero (1e-15).
If you want to understand FFT and DFT in more detail read a textbook of signal analysis for electrical engineering.

Although ... you must be a good expert now :)
For others: Please notice that
with this set of Correct mathematical equation
so correcting the sum as:
signal1 = \
1 *np.cos(2*np.pi * t) *\
2 *np.cos(2*np.pi * 4*t) *\
0.5 *np.cos(2*np.pi * 0.5*t)
signal2 = \
0.25*np.cos(-2*np.pi * 2.5*t) +\
0.25*np.cos(2*np.pi * 3.5*t) +\
0.25*np.cos(-2*np.pi * 4.5*t) +\
0.25*np.cos(2*np.pi * 5.5*t)
Now gives following result
(Now results are)
So point is that real part should also be the same

Related

Matplotlib.odeint giving wrong solution for simple formula of acc = Gm/r**2

I made a program to calculate the motion of any object (in this case moon) by earth's pull, with zero initial velocity, the moon should just oscillate in a straight line back and forth the earth until it stops at earth exactly right on top of the Earth, so plotting time versus distance I should get a graph similar to a damping signal, instead, I am getting an infinitely decrementing plot.
I have tried :-
giving different initial speeds to the moon, but got the same result, it seems like the way I am using odeint to solve the differential equation is wrong? Not sure. Very new to coding.
Assuming 1000 seconds in not enough for this to happen, so I increased the time to 1e+5,1e+10,1e+20, it seems like odeint couldn't handle that because it gave a different solution every time I run the program for the exact same parameters, received the follow warning:
ODEintWarning: Excess work done on this call (perhaps wrong Dfun type). Run with full_output = 1 to get quantitative information. warnings.warn(warning_msg, ODEintWarning)
Is there some other function I should use to solve this differential equation?
Reduced the masses to 10,20 and G and r to 10,10, and received the same warning as in case (2)
Any feed back helps
from scipy.integrate import odeint
import matplotlib.pyplot as plt
G=6.67408e-11 #N-m2/kg2 #N-m2/kg2
m1 = 5.972e+24 # kg , mass of earth
m2 = 7.348e+22 # kg , mass of moon
def dvdt(S, t):
# v = dr./dt, so a = dv/dt
r,v = S
return [v,
-G*m1 / r**2]
# initial values
r10 = 0 # position of earth in meters
r20 = 4e+8 # position of moon from earth in meters
v10 = 0 # velocity of earth m/s
v20 = 0 # velocity of moon relative to earth m/s
S0 = [r20, v20]
t = np.linspace(0,1000,100)
# solving the differential eqn
acc = odeint(dvdt,S0, t)
r,v = acc.T
# plotting
plt.plot(t,r)
plt.xlabel('Time')
plt.ylabel('Distance between earth and moon')
plt.show()
The scenario assumes that the two bodies are "shifted out of phase", so that they behave like dark matter to each other, no electro-weak or strong nuclear forces.
The effective gravity below the radius of Earth is determined by the mass inside the current radius, the influences of the outer shell add to zero.
The force vector always points to the center, for the one-dimensional motion the sign of the force has always to be opposite to the sign of the coordinate.
In total thus
R1 = 6.7e+6 # m
acc = -sign(r) * G*(m1*min(1,abs(r)/R1)**3) / abs(r)**2
= -G*m1 * r/max(R1,abs(r))**3
If this is implemented, one gets the expected oscillating plot

How to recover amplitude, and phase shift from Fourier Transform in Numpy?

I'm trying to write a simple python script that recovers the amplitude and phase of a sine wave from it's fourier transformation.
I should be able to do this by calculating the magnitude, and direction of the vector defined by the real and imaginary numbers for the fourier transform, for a given frequency, i.e:
Amplitude_at_freq = sqrt(real_component_at_freq^2 + imag_component_at_freq^2)
Phase = arctan(imag_component_at_freq/real_component_at_freq)
Ref: 1 min 45 seconds into this video: https://www.youtube.com/watch?time_continue=106&v=IWQfj05i87g
I've written a simple python script using numpy's fft library to try and reproduce this, but despite writing out my derivation exactly as above, am failing to get the amplitude and phase, although I can recover the original frequency of my test sine wave correctly. This previous post Calculating amplitude from np.fft and this one Why FFT does not retrieve original amplitude when increasing signal length points to the same problem (where amplitude is off by factor of 2). Specifically the solution is to "multiply by 2 (half of spectrum is removed so energy must be preserved)," but I need clarification on what that means. Secondly there's no mention of my issue with recovering the phase change, and the amplitude is calculated differently from what I have here.
# Define amplitude, phase, frequency
_A = 4 # Amplitude
_p = 0 # Phase shift
_f = 8 # Frequency
# Construct a simple signal
t = np.linspace(0, 2*np.pi, 1024 + 1)[:-1]
g = _A * np.sin(_f * t + _p)
# Apply the fourier transform
ff = np.fft.fft(g)
# Get frequency of original signal
ff_ii = np.where(np.abs(ff) > 1.0)[0][0] # Just get one frequency, the other one is just mirrored freq at negative value
print('frequency of:', ff_ii)
# Get the complex vector at that frequency to retrieve amplitude and phase shift
yy = ff[ff_ii]
# Calculate the amplitude
T = t.shape[0] # domain of x; which we will divide height to get freq amplitude
A = np.sqrt(yy.real**2 + yy.imag**2)/T
print('amplitude of:', A)
# Calculate phase shift
phi = np.arctan(yy.imag/yy.real)
print('phase change:', phi)
However, the result I'm getting is:
>> frequency of: 8
>> amplitude of: 2.0
>> phase change: 1.5707963267948957
So the frequency is accurate, but I'm getting an amplitude of 2, when it should be 4, and phase change of pi/2, when it should be zero.
Is my math wrong, or is my understanding of numpy's fft implementation incorrect?
Fourier analyses a signal as a sum of exp(i.2.pi.f.t) terms, so it sees
A.sin(2.pi.f1.t) as:
-i.A/2.exp(i.2.pi.f1.t)+i.A/2.exp(-i.2.pi.f1.t),
which is mathematically equal. So in Fourier terms, you have both the positive frequency f1 and negative -f1 with complex values -A/2.i and A/2.i respectively. So each 'side' has only half the amplitude, but if you add them together (in the inverse Fourier transform) you get back amplitude A. This split in positive and negative frequency is where your missing factor 2 is if you only look at one (positive or negative) side of the spectrum. This is often done in practice because for real signals, the other half is trivial to derive given one.
Look into the exact mathematics Euler's formula and Fourier transform.

Zoom in on np.fft2 result

Is there a way to chose the x/y output axes range from np.fft2 ?
I have a piece of code computing the diffraction pattern of an aperture. The aperture is defined in a 2k x 2k pixel array. The diffraction pattern is basically the inner part of the 2D FT of the aperture. The np.fft2 gives me an output array same size of the input but with some preset range of the x/y axes. Of course I can zoom in by using the image viewer, but I have already lost detail. What is the solution?
Thanks,
Gert
import numpy as np
import matplotlib.pyplot as plt
r= 500
s= 1000
y,x = np.ogrid[-s:s+1, -s:s+1]
mask = x*x + y*y <= r*r
aperture = np.ones((2*s+1, 2*s+1))
aperture[mask] = 0
plt.imshow(aperture)
plt.show()
ffta= np.fft.fft2(aperture)
plt.imshow(np.log(np.abs(np.fft.fftshift(ffta))**2))
plt.show()
Unfortunately, much of the speed and accuracy of the FFT come from the outputs being the same size as the input.
The conventional way to increase the apparent resolution in the output Fourier domain is by zero-padding the input: np.fft.fft2(aperture, [4 * (2*s+1), 4 * (2*s+1)]) tells the FFT to pad your input to be 4 * (2*s+1) pixels tall and wide, i.e., make the input four times larger (sixteen times the number of pixels).
Begin aside I say "apparent" resolution because the actual amount of data you have hasn't increased, but the Fourier transform will appear smoother because zero-padding in the input domain causes the Fourier transform to interpolate the output. In the example above, any feature that could be seen with one pixel will be shown with four pixels. Just to make this fully concrete, this example shows that every fourth pixel of the zero-padded FFT is numerically the same as every pixel of the original unpadded FFT:
# Generate your `ffta` as above, then
N = 2 * s + 1
Up = 4
fftup = np.fft.fft2(aperture, [Up * N, Up * N])
relerr = lambda dirt, gold: np.abs((dirt - gold) / gold)
print(np.max(relerr(fftup[::Up, ::Up] , ffta))) # ~6e-12.
(That relerr is just a simple relative error, which you want to be close to machine precision, around 2e-16. The largest error between every 4th sample of the zero-padded FFT and the unpadded FFT is 6e-12 which is quite close to machine precision, meaning these two arrays are nearly numerically equivalent.) End aside
Zero-padding is the most straightforward way around your problem. But it does cost you a lot of memory. And it is frustrating because you might only care about a tiny, tiny part of the transform. There's an algorithm called the chirp z-transform (CZT, or colloquially the "zoom FFT") which can do this. If your input is N (for you 2*s+1) and you want just M samples of the FFT's output evaluated anywhere, it will compute three Fourier transforms of size N + M - 1 to obtain the desired M samples of the output. This would solve your problem too, since you can ask for M samples in the region of interest, and it wouldn't require prohibitively-much memory, though it would need at least 3x more CPU time. The downside is that a solid implementation of CZT isn't in Numpy/Scipy yet: see the scipy issue and the code it references. Matlab's CZT seems reliable, if that's an option; Octave-forge has one too and the Octave people usually try hard to match/exceed Matlab.
But if you have the memory, zero-padding the input is the way to go.

Fourier transform and filtering frequencies with negative fft values

I'm looking for the most abundant frequency in a periodic signal.
I'm trying to understand what do I get if I perform a Fourier transformation on a periodic signal and filter for frequencies which have negative fft values.
In other words, what do the axis of plots 2 and 3 (see below) express? I'm plotting frequency (cycles/second) over the fft-transformed signal - what do negative values on the y axis mean, and would it make sense that I'd be interested in only those?
import numpy as np
import scipy
# generate data
time = scipy.linspace(0,120,4000)
acc = lambda t: 10*scipy.sin(2*pi*2.0*t) + 5*scipy.sin(2*pi*8.0*t) + 2*scipy.random.random(len(t))
signal = acc(time)
# get frequencies from decomposed fft
W = np.fft.fftfreq(signal.size, d=time[1]-time[0])
f_signal = np.fft.fft(signal)
# filter signal
# I'm getting only the "negative" part!
cut_f_signal = f_signal.copy()
# filter noisy frequencies
cut_f_signal[(W < 8.0)] = 0
cut_f_signal[(W > 8.2)] = 0
# inverse fourier to get filtered frequency
cut_signal = np.fft.ifft(cut_f_signal)
# plot
plt.subplot(221)
plt.plot(time,signal)
plt.subplot(222)
plt.plot(W, f_signal)
plt.subplot(223)
plt.plot(W, cut_f_signal)
plt.subplot(224)
plt.plot(time, cut_signal)
plt.show()
The FFT of a real-valued input signal will produce a conjugate symmetric result. (That's just the way the math works best.) So, for FFT result magnitudes only of real data, the negative frequencies are just mirrored duplicates of the positive frequencies, and can thus be ignored when analyzing the result.
However if you want to do the inverse and compute the IFFT, you will need to feed the IFFT a conjugate symmetric negative half (or upper half, above Fs/2) of frequency data, or else your IFFT result will end up producing a complex result (e.g. with non-zero imaginary (sqrt(-1)) components, rarely what one want when dealing with base-band real data).
If you want to filter the FFT data and end up with real results from an IFFT, you will need to filter the positive and negative frequencies symmetrically identically to maintain the needed symmetry.
The FFT also produces a complex result, where the value and sign the components (real and imaginary) of each result bin represents the phase as well as the magnitude of the component basis vector (complex sinusoid, or real cosine plus real sine components). Any negative value just represents a phase rotation from if the same result was positive.
As #hotpaw2 already wrote in his comment above, the result of a FFT performed on a real signal in time domain generates complex values in frequency domain.
The input value f_signal of your plot command is a vector of complex values.
plt.subplot(222)
plt.plot(W, f_signal)
This results in meaningless output.
You should plot the absolute values of f_signal.
If you are interested in the phase you should plot the angle, too.
In Matlab this would look like this:
% Plot the absolute values of f_signal
plot(W, abs(f_signal));
% Plot the phase of f_signal
plot(W, (unwrap(angle(f_signal)));

comparing two frequency spectra

I'm trying to compare two frequency spectra but I am confused over a number of points.
One device samples at 40 Hz the other at 100 Hz and so I'm not sure if I need to take this into account. Anyway I have produced frequency spectra from both devices and now I wish to compare these. How can I do correlation at each point so that I get pearson correlations at each point. I know how to do an overall one of course but I want to see points of strong correlation and those less strong?
If you are calculating power spectral densities P(f), then it doesn't matter how your original signal x(t) is sampled. You can directly and quantitatuively compare both spectra. To make sure that you have calculated the spectral densities you can explicitly check Parsevals theorem:
$ \int P(f) df = \int x(t)^2 dt $
Of course you have to think about which frequencies are actually evaluated Remember that a fft gives you frequencies from f = 1/T until or below the Nyquist frequency f_ny = 1/(2 dt) depending on the number of samples in x(t) being even or odd.
Here's a python example code for psd
def psd(x,dt=1.):
"""Computes one-sided power spectral density of x.
PSD estimated via abs**2 of Fourier transform of x
Takes care of even or odd number of elements in x:
- if x is even both f=0 and Nyquist freq. appear once
- if x is odd f=0 appears once and Nyquist freq. does not appear
Note that there are no tapers applied: This may lead to leakage!
Parseval's theorem (Variance of time series equal to integral over PSD) holds and can be checked via
print ( np.var(x), sum(Px*f[1]) )
Accordingly, the etsimated PSD is independent of time series length
Author/date: M. von Papen / 16.03.2017
"""
N = np.size(x)
xf = np.fft.fft(x)
Px = abs(xf)**2./N*dt
f = np.arange(N/2+1)/(N*dt)
if np.mod(N,2) == 0:
Px[1:N/2] = 2.*Px[1:N/2]
else:
Px[1:N/2+1] = 2.*Px[1:N/2+1]
# Take one-sided spectrum
Px = Px[0:N/2+1]
return Px, f