Calculate the magnitude and phase of a signal at a particular frequency in python

I have a signal for which I need to calculate the magnitude and phase at 200 Hz frequency only. I would like to use Fourier transform for it. I am very new to signal processing. And this is my first time using a Fourier transform.

I found that I can use the scipy.fftpack.fft to calculate the FFT of the signal. Then use numpy.mag and numpyh.phase to calculate the magnitude and phases of the entire signal. But I would like to get the magnitude and phase value of the signal corresponding to 200 Hz frequency only. How can I do this using Python?

So far I have done.

from scipy.fftpack import fft
import numpy as np

fft_data = fft(signal)
magnitude = np.mag(fft_data)
phase = np.phase(fft_data)
• Welcome to SE.SP! Do you know the sampling frequency of your data?
– Peter K.
Dec 14 '20 at 19:12
• the sampling frequency is 2 MHz Dec 15 '20 at 1:41
• What do you have to separate it from? What is the rest of the signal that is not 200Hz?
– IanJ
Dec 15 '20 at 3:08
• I'm not interested in other frequencies. Dec 15 '20 at 3:25

You can find the index of the desired (or the closest one) frequency in the array of resulting frequency bins using np.fft.fftfreq function, then use np.abs and np.angle functions to get the magnitude and phase.

Here is an example using fft.fft function from numpy library for a synthetic signal.

import numpy as np
import matplotlib.pyplot as plt

# Number of sample points
N = 1000

# Sample spacing
T = 1.0 / 800.0     # f = 800 Hz

# Create a signal
x = np.linspace(0.0, N*T, N)
t0 = np.pi/6   # non-zero phase of the second sine
y = np.sin(50.0 * 2.0*np.pi*x) + 0.5*np.sin(200.0 * 2.0*np.pi*x + t0)
yf = np.fft.fft(y) # to normalize use norm='ortho' as an additional argument

# Where is a 200 Hz frequency in the results?
freq = np.fft.fftfreq(x.size, d=T)
index, = np.where(np.isclose(freq, 200, atol=1/(T*N)))

# Get magnitude and phase
magnitude = np.abs(yf[index])
phase = np.angle(yf[index])
print("Magnitude:", magnitude, ", phase:", phase)

# Plot a spectrum
plt.plot(freq[0:N//2], 2/N*np.abs(yf[0:N//2]), label='amplitude spectrum')   # in a conventional form
plt.plot(freq[0:N//2], np.angle(yf[0:N//2]), label='phase spectrum')
plt.legend()
plt.grid()
plt.show()

And here is a useful manual with detailed explanations: reference.

• thank you for the clear explanation. I have two doubts. 1. What should I do if I want to change the phase of the signals to 30 degrees? 2. Why are you not scaling the magnitude values with (2/N)? Dec 18 '20 at 11:11
• @thileepan 1. The phase t0 would be an additional term in the argument of a sine: A*sin(wt+t0). t0 = np.pi/6 should shift the signal to 30 degrees. 2. The example shows the default fft results. You can normalize the magnitude by setting the "norm" parameter like this: yf = np.fft.fft(y, norm='ortho'). Btw, my bad, np.isclose does not work as intended. I will fix it in the answer. Dec 18 '20 at 14:03
• @thileepan Regarding the normalization of the results, you may find this question to be helpful. Dec 18 '20 at 14:33
• Silly question (probably): I ran the code, and the output for the phase is phase: -0.2672456406675483, but you had set it up to be t0 = np.pi/6 # non-zero phase of the second sine. This is 0.5235987755982988. Why are they not the same? yesterday