How can I transfer a discrete signal from the time domain into the frequency domain and back without losing data?

StackOverflow https://stackoverflow.com/questions/7141514

Question

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

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top