[英]How to add a phase shift to a sin wave in the frequency domain with fft?
I want to shift a sine wave in the frequency domain我想在频域中移动正弦波
My idea is the following:我的想法如下:
In code:在代码中:
t=np.arange(0, 6 , 0.001)
values = A*np.sin(t)
ft_values= np.fft.fft(values)
ft_values_phase=ft_values+1j*np.pi
back_again= np.fft.ifft(ft_values_phase)
plt.subplot(211)
plt.plot(t,values)
plt.subplot(212)
plt.plot(t,back_again)
I expected two images, in which one wave is shifted by pi, however I got this result我期望两个图像,其中一个波被 pi 移动,但是我得到了这个结果
(no phase shift): (无相移):
Thank you for any help!感谢您的任何帮助!
You did not made a phase shift.您没有进行相移。
What you did was to add a 6000-vector, say P , with constant value P(i) = j π to V , the FFT of v .您所做的是添加一个 6000 向量,例如P ,具有恒定值P(i) = j π 到V ,即v的 FFT。
Let's write Ṽ = V + P .让我们写Ṽ = V + P 。
Due to linearity of the FFT (and of IFFT), what you have called back_again
is由于 FFT(和 IFFT)的线性,你所说的
back_again
是
ṽ = IFFT(Ṽ) = IFFT(V) + IFFT(P) = v + p ṽ = IFFT(Ṽ) = IFFT(V) + IFFT(P) = v + p
where, of course, p = IFFT(P) is the difference values-back_again
— now, let's check what is p ...其中,当然, p = IFFT(P)是差值
values-back_again
— 现在,让我们检查一下p是什么......
In [51]: P = np.pi*1j*np.ones(6000)
...: p = np.fft.ifft(P)
...: plt.plot(p.real*10**16, label='real(p)*10**16')
...: plt.plot(p.imag, label='imag(p)')
...: plt.legend();
As you can see, you modified values
by adding a real component of ṽ that is essentially numerical noise in the cumputation of the IFFT (hence no change in the plot, that gives you the real part of back_again
) and a single imaginary spike, its height unsurprisingly equal to π, for t=0 .如您所见,您通过添加ṽ的实部分量来修改
values
,该实部分量本质上是 IFFT 计算中的数值噪声(因此图中没有变化,它为您提供back_again
的实部)和单个假想尖峰,它的毫不奇怪,高度等于 π,因为t=0 。
The transform of a constant is a spike at ω=0 , the antitransform of a constant (in frequency domain) is a spike at t=0 .常数的变换是ω=0处的尖峰,常数(在频域中)的反变换是t=0处的尖峰。
As I said in a deleted comment if you do not add a constant to each FFT term but multiply them by a constant you also multiply the signal by the same constant (remember, FFT and IFFT are linear).正如我在已删除的评论中所说,如果您不向每个 FFT 项添加一个常数,而是将它们乘以一个常数,那么您还将信号乘以相同的常数(请记住,FFT 和 IFFT 是线性的)。
To do what you want, you have to remember that a shift in the time domain is just the (circular) convolution of the (periodic) signal with a time-shifted spike, so you have to multiply the FFT of the signal by the FFT of the shifted spike.为了做你想做的事,你必须记住时域的偏移只是(周期性)信号与时移尖峰的(圆形)卷积,所以你必须将信号的 FFT 乘以 FFT移动的尖峰。
Because the Fourier Transform of a Dirac Distribution δ(ta) is exp(-iωa) you have to multiply each term of the FFT of the signal by a frequency dependent term.由于狄拉克分布δ(ta)的傅立叶变换是exp(-iωa),因此您必须将信号 FFT 的每一项乘以频率相关项。
An Example一个例子
Some preliminaries一些预赛
In [61]: import matplotlib.pyplot as plt
...: import numpy as np
In [62]: def multiple_formatter(x, pos, den=60, number=np.pi, latex=r'\pi'):
... # search on SO for an implementation
In [63]: def plot(t, x):
...: fig, ax = plt.subplots()
...: ax.plot(t, x)
...: ax.xaxis.set_major_formatter(plt.FuncFormatter(multiple_formatter))
...: ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
...: ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 4))
A function to compute the discrete FT of a Dirac Distribution centered in n
for a period N
用于计算以
n
为中心的狄拉克分布的离散 FT 的函数,时间为N
In [64]: def shift(n, N):
...: s = np.zeros(N)
...: s[n] = 1.0
...: return np.fft.fft(s)
Let's plot a signal and the shifted signal让我们绘制一个信号和移位的信号
In [65]: t = np.arange(4096)*np.pi/1024
In [66]: v0 = np.sin(t)
In [67]: v1 = np.sin(t-np.pi/4)
In [68]: f, a = plot(t, v0)
In [69]: a.plot(t, v1, label='shifted by $\\pi/4$');
In [70]: a.legend();
Now compute the FFT of the correct spike (note that π/4 = (4π)/16 ), the FFT of the shifted signal, the IFFT of the FFT of the ss and finally plot our results现在计算正确尖峰的 FFT(注意π/4 = (4π)/16 )、移位信号的 FFT、ss 的 FFT 的 IFFT,最后绘制我们的结果
In [71]: S = shift(4096//16-1, 4096)
In [72]: VS = np.fft.fft(v0)*S
In [73]: vs = np.fft.ifft(VS)
In [74]: f, ay = plot(t, v0)
In [75]: ay.plot(t, vs.real, label='shifted in frequency domain');
In [76]: ay.legend();
Nice, that helped!不错,有帮助! For anyone who wants to do the same, here is it in one python file:
对于任何想要做同样事情的人,这里有一个 python 文件:
import numpy as np
from matplotlib.pyplot import plot, legend
def shift(n, N):
s = np.zeros(N)
s[n] = 1.0
return np.fft.fft(s)
t = np.linspace(0, 2*np.pi,1000)
v0 = np.sin(t)
S = shift(1000//4, 1000) # shift by pi/4
VS = np.fft.fft(v0)*S
vs = np.fft.ifft(VS)
plot(t, v0 , label='original' )
plot(t,vs.real,label='shifted in frequency domain')
legend()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.