2

几个星期以来,我一直在尝试实现一个 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]);
}

身份证:

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]));
}

任何人都可以帮我确定问题所在吗?

我之前问过一个关于同一个项目的问题,但措辞很糟糕,编辑可能会造成更多的混乱,而不是更少。此外,虽然这个问题可能已经得到解答,但我还有更多需要弄清楚。可以在这里找到

4

2 回答 2

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 是线性代数,您可能会得到它不是完全正确的,但仍然会看到看起来质量不错的答案。

于 2011-08-22T07:19:25.787 回答
1

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

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

如果您丢弃任何项(复杂的虚项或频率区间或其他),结果将与原始项相去甚远。例如,如果您的 frequency_domain_magnitude.length 或您的 freqUsed.length 小于您的数据长度,您将丢弃术语(除非您使用稍微不同的算法和/或比例因子)。

正如@ellisbben 所提到的,您的 IDFT 中也至少有 1 或 2 个致命的拼写错误。

于 2011-08-22T21:50:19.417 回答