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

发布于 2024-11-30 14:08:11 字数 1319 浏览 2 评论 0原文

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

我一直在遵循 维基百科方程 作为如何执行此操作的指南,我的代码似乎匹配给定以下代码的方程(在我的脑海中):

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

任何人都可以帮助我确定问题是什么?

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

For a few weeks now, I have been trying to implement a DFT that takes an arbitrary set of bytes and treats them as a signal. It then transforms them to the frequency domain. Following that it transforms them back. It originally only attempted to use some of the components to reconstruct the original signal. When this failed, I tried using all of the components and it still failed.

I have been following Wikipedia's Equations as a guide for how to do this and my code seems to match the equations given (in my mind) given this code:

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

Can anybody help me identify what the problem is?

I asked a previous question that is about the same project, but it was worded terribly and editing may have caused more confusion, not less. Also, although that question may have been answered, I still have more to figure out. That can be found here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痴意少年 2024-12-07 14:08:11

至少有三件事是错误的:

首先,您没有对 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 是线性代数,因此您可能会得到不太正确的结果,但仍然会看到质量上看起来不错的答案。

At least three things are wrong:

First, you are not summing over all frequencies in your IDFT. That's a big, big problem, basically equivalent to only taking the IDFT of one discrete frequency instead of the entire frequency domain data.
Second, you have a sign flipped in your IDFT.

Change line 5 of snippet 2 to

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

and make sure you initialize doubleValue to zeros.

Third, you'll want to add a normalization step;

Change line 7 of snippet 2 to

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

Fourth, for your own ease, test this floating point algorithm using floating point inputs and outputs before you truncate to an integral data type and don't assume that you'll get precisely correct answers doing a round trip on integral data-- floating point error is very real.

It might also help to grab someone else's implementation of the DFT and IDFT and compare the behavior with your implementation on some very simple inputs to catch other errors. Since the DFT is linear algebra, you may get it less than perfectly correct and still see qualitatively okay-seeming answers.

赴月观长安 2024-12-07 14:08:11

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

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

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

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

In the numerical sense, you can't, as rounding and/or quantization errors will almost always produce slight differences or information losses during the round trip.

However, if you implement the DFT and IDFT correctly and completely, the time domain data can be recreated within this numerical error. It is possible that an FFT/IFFT pair will produce smaller numerical errors than a DFT/IDFT pair.

If you throw away any terms (complex imaginary terms or frequency bins or otherwise), the result will be farther from the original. For instance, if your frequency_domain_magnitude.length or your freqUsed.length is less than your data length, you will have thrown away terms (unless you use a slightly different algorithm and/or scale factors).

There are also at least 1 or 2 fatal typos in your IDFT, as mentioned by @ellisbben.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文