实对称矢量的FFT不是真实的和对称的

时间:2014-07-30 16:43:31

标签: matlab signal-processing fft dft symmetric

我很难理解应该是一个简单的概念。我在MATLAB中构造了一个真实且对称的向量。当我在MATLAB中进行FFT时,结果具有显着的虚部,即使傅里叶变换的对称规则说实际对称函数的FT也应该是实数和对称的。我的示例代码:

N = 1 + 2^8;
k = linspace(-1,1,N);

V = exp(-abs(k));

Vf1 = fft(fftshift(V));
Vf2 = fft(ifftshift(V));
Vf3 = ifft(fftshift(V));
Vf4 = ifft(ifftshift(V));
Vf5 = fft(V);
Vf6 = ifft(V);

disp([isreal(Vf1) isreal(Vf2) isreal(Vf3) isreal(Vf4) isreal(Vf5) isreal(Vf6)])

结果:

0 0 0 0 0 0

(i)fft(i)fftshift的任何组合都不会产生真正的对称向量。我尝试了偶数和奇数N(N = 2^8N = 1+2^8)。

我确实尝试过查看k+flip(k)并且eps(1)的顺序有一些残差,但残差也是对称的,并且FFT的虚部不是在命令中出现的模糊eps(1)的{​​{1}},但幅度可与实际部分相比。

我错过了一件令人眼花缭乱的明显事情?

我错过了令人目眩的明显事情:

FFT不是所有空间的积分,因此它假定为周期性信号。在上面,我复制了我选择偶数N时期间的最后一点,因此没有办法将它移动到零开始,而没有小数索引,这是不存在的。< / p>

关于我选择k的一句话。这不是任意的。我试图解决的实际问题是生成模型FTIR干涉图,然后我将进行FFT以获得光谱。 k是干涉仪行进的距离,它在波数中转换为频率。在实际问题中,将存在各种缩放因子,使得生成函数V将产生物理上有意义的数字。

4 个答案:

答案 0 :(得分:8)

这是

Vf = fftshift(fft(ifftshift(V)));

也就是说,您需要在时域中ifftshift,以便将样本解释为对称函数的样本,然后在频域中fftshift再次使对称明显。

这仅适用于N奇数。对于N偶数,对称函数的概念没有意义:没有办法移动信号使其相对于原点对称(原点需要“在两个样本之间”,这是不可能的。)

对于您的示例V,上面的代码使Vf真实且对称。使用semilogy(Vf)生成了下图,因此可以看到小值和大值。 (当然,您可以修改水平轴,使图形以0的频率居中;但无论如何,图形看起来是对称的。)

enter image description here

答案 1 :(得分:5)

@Yvon对于对称性的评论是绝对正确的。您的输入信号看起来是对称的,但它并不是因为对称性与原点0有关。 在Matlab中使用 linspace 构建信号通常是一个糟糕的选择。 尝试用fftshift修复结果也是一个坏主意。

改为使用:

k = 2*(0:N-1)/N - 1;

你会得到你期望的结果。 然而,变换值的虚部不会完全为零。 有一些数字噪音。

>> max(abs(imag(Vf5)))
ans =
2.5535e-15

回答Yvon的问题:

  

为什么呢? &GT;&GT; N = 1 + 2 ^ 4 N = 17> x = linspace(-1,1,N)x = -1.0000 -0.8750 -0.7500 -0.6250 -0.5000 -0.3750 -0.2500 -0.1250 0 0.1250 0.2500 0.3750 0.5000 0.6250 0.7500 0.8750 1.0000&gt; y = 2 *(0:N-1)/ N-1 y = -1.0000 -0.8824 -0.7647 -0.6471 -0.5294 -0.4118 -0.2941 -0.1765 -0.0588 0.0588 0.1765 0.2941 0.4118 0.5294 0.6471 0.7647 0.8824 - Yvon 1

您的示例不是对称(偶数)函数,而是反对称(奇数)函数。但是,这没什么区别。

对于长度为N的反对称函数,以下陈述为真:

f[i] == -f[-i] == -f[N-i]

索引i从0运行到N-1。

让我们看看i = 2时发生了。请记住,count从0开始,以16结束。

x[2] = -0.75
-x[N-2] == -x[17-2] == -x[15] = (-1) 0.875 = -0.875
x[2] != -x[N-2]

y[2] = -0.7647
-y[N-2] == -y[15] = (-1) 0.7647
y[2] == y[N-2]

问题是,Matlab向量的起源从1开始。 模(周期)向量以原点0开始。 这种差异导致了许多误解。

另一种解释为什么linspace(-1,+ 1,N)不正确的方法:

想象一下,你有一个矢量,它包含一个周期函数的周期, 例如Cosinus函数。这个单一时期是无数个时期之一。 Cosinus矢量的第一个值不能与矢量的最后一个值相同。 然而,这正是linspace(-1,+ 1,N)所做的。 这样做会产生一个序列,其中句点1的最后一个值与下一个句点2的第一个样本的值相同。这不是您想要的。 为避免这种错误,使用t = 2 *(0:N-1)/ N - 1.距离t [i + 1] -t [i]为2 / N,最后一个值必须为t [N-1] ] = 1 - 2 / N而不是1.

回答Yvon的第二条评论

无论你在DFT / FFT的输入矢量中放置什么,理论上它都被解释为周期函数。 但这不是重点。

DFT执行集成。

fft(m) = Sum_(k=0)^(N-1) (x(k) exp(-i 2 pi m k/N )

第一个值x(k = 0)描述长度为1 / N的第一积分区间的幅度。第二值x(k = 1)描述长度为1 / N的第二积分区间的幅度。等等。

对称函数的最后一个积分区间结束,其值与第一个样本相同。这意味着,最后一个积分区间的起点是k = N-1 = 1-1 / N.输入向量包含积分区间的起点

因此,最后一个对称点k = N是函数的一个点,但它不是积分区间的起点,因此它不是输入向量的成员。

答案 2 :(得分:2)

在实现概念&#34; symmetry&#34;时遇到问题。纯粹的真实,偶数(或#34;对称&#34;)函数具有傅里叶变换函数,该函数也是真实的和偶数的。 &#34;即使&#34;是相对于y轴或t = 0线的对称性。

但是,在Matlab中实现信号时,总是从t = 0开始。也就是说,没有办法定义&#34;信号从时间原点开始。

在网上搜索一段时间会引导我这个 - Correct use of fftshift and ifftshift at input to fft and ifft

由于路易斯有pointed out,您需要在将信号输入fft之前执行ifftshift。原因从未在Matlab中记录,但只在该线程中记录。由于历史原因,交换了fftifft的输出AND 输入。也就是说,而不是从-N/2N/2-1(自然顺序)排序,时域或频域中的信号从0N/2-1 排序,然后 -N/2-1。这意味着,代码的正确方式为fft( ifftshift(V) ),但大多数人在大多数情况下忽略此。为什么它被默默地忽略而不是提出巨大的问题是大多数关注点都放在信号的幅度上,而不是相位上。由于循环移位不会影响幅度谱,因此这不是问题(即使对于编写文档的Matlab人员也是如此)。

检查幅度相等 -

Vf2 = fft(ifftshift(V));
Vf5 = fft(V);
Va2 = abs(fftshift(Vf2));
Va5 = abs(fftshift(Vf5));

>> min(abs(Va2-Va5)<1e-10)

ans =

     1

看看阶段有多么糟糕 -

Vp2 = angle(fftshift(Vf2));
Vp5 = angle(fftshift(Vf5));

无论如何,正如我在评论中写的那样,在将代码复制并粘贴到一个清新干净的Matlab之后,它会给出0 1 0 1 0 0

关于N =偶数和N =奇数的问题,我的观点是当N =偶数时,信号不对称,因为在时间原点的两边有不等数量的点。

答案 3 :(得分:2)

在&#34; k = linspace(-1,1,N)之后添加以下行;&#34;

k(end)=[];

它将删除数组的最后一个元素。这被定义为对称数组。

还要考虑isreal(complex(1,0))是假的!!! isreal函数只检查内存存储格式。所以在上面的例子中,1 + 0i并不真实。

您已定义功能以检查实数(如此)

myisreal=@(x) all((abs(imag(x))<1e-6*abs(real(x)))|(abs(x)<1e-8));

最后你的源代码应该是这样的:

N = 1 + 2^8;
k = linspace(-1,1,N);

k(end)=[];

V = exp(-abs(k));


Vf1 = fft(fftshift(V));

Vf2 = fft(ifftshift(V));
Vf3 = ifft(fftshift(V));
Vf4 = ifft(ifftshift(V));
Vf5 = fft(V);
Vf6 = ifft(V);

myisreal=@(x) all((abs(imag(x))<1e-6*abs(real(x)))|(abs(x)<1e-8));

disp([myisreal(Vf1) myisreal(Vf2) myisreal(Vf3) myisreal(Vf4) myisreal(Vf5) myisreal(Vf6)]);