如何将离散信号从时域传输到频域并返回而不会丢失数据?

时间:2011-08-21 22:12:48

标签: math signal-processing fft frequency-analysis dft

几周以来,我一直在尝试实现一个DFT,它接受一组任意字节并将它们视为一个信号。然后它将它们转换到频域。然后它将它们转换回来。它最初只试图使用一些组件来重建原始信号。如果失败,我尝试使用所有组件,但仍然失败。

我一直关注Wikipedia's Equations作为如何执行此操作的指南,我的代码似乎与给出此代码时给出的等式(在我看来)相符:

DFT:

for (int k = 0; k < frequency_domain_magnitude.length; k++) {
    for (int n = 0; n < data.length; n++) {
        double val = (-2.0 * Math.PI * n * k / data.length);
        freq_imag[k] += data[n] * -Math.sin(val);
        freq_real[k] += data[n] * Math.cos(val);
    }
    frequency_domain_magnitude[k] = Math.sqrt(freq_imag[k] * freq_imag[k] + freq_real[k] * freq_real[k]);
}

IDFT:

for (int n = 0; n < data.length; n++) {
    doubleValue[n] = 0;
    for (int k = 0; k < freqUsed.length; k++) {
        double val = (2.0 * Math.PI * n * k / data.length);
        doubleValue[n] = freq_real[k] * Math.cos(val) - freq_imag[k] * Math.sin(val);
    }
    time_real[n] = (byte) (Math.floor(doubleValue[n]));
}

有人可以帮我确定问题所在吗?

我问了一个关于同一个项目的上一个问题,但措辞非常糟糕,编辑可能会造成更多的混乱,而不是更少。此外,虽然这个问题可能已得到解答,但我还有更多要弄清楚。可以找到here

2 个答案:

答案 0 :(得分:3)

至少有三件事是错的:

首先,您没有对IDFT中的所有频率进行求和。这是一个很大的问题,基本上相当于只采用一个离散频率的IDFT而不是整个频域数据。 其次,你的IDFT中有一个标志翻转。

将代码段2的第5行更改为

    doubleValue[n] += freq_real[k] * Math.cos(val) + freq_imag[k] * Math.sin(val);

并确保将doubleValue初始化为零。

第三,您需要添加规范化步骤;

将代码段2的第7行更改为

time_real[n] = (byte) (Math.floor(doubleValue[n] / data.length))

第四,为了您自己的方便,在截断为整数数据类型之前使用浮点输入和输出测试此浮点算法,并且不要假设您将获得对整数数据进行往返的精确正确答案 - - 浮点误差非常真实。

它可能也有助于获取其他人的DFT和IDFT的实现,并将一些非常简单的输入上的行为与您的实现进行比较以捕获其他错误。由于DFT是线性代数,你可能会得到它不是完全正确的,仍然可以看到质量好的看似答案。

答案 1 :(得分:1)

在数字意义上,你不能,因为在往返过程中舍入和/或量化误差几乎总会产生轻微的差异或信息损失。

但是,如果正确且完整地实现DFT和IDFT,则可以在此数字错误中重新创建时域数据。 FFT / IFFT对可能产生比DFT / IDFT对更小的数值误差。

如果您丢弃任何术语(复杂的虚构术语或频率分类或其他),结果将远离原始术语。例如,如果你的frequency_domain_magnitude.length或你的freqUsed.length小于你的数据长度,你就会抛弃术语(除非你使用稍微不同的算法和/或比例因子)。

如@ellisbben所述,您的IDFT中至少还有1或2个致命错误。