Как я могу передать дискретный сигнал из временной области в частотную область и обратно без потери данных? - PullRequest
2 голосов
/ 22 августа 2011

Уже несколько недель я пытаюсь реализовать 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]));
}

Может кто-нибудь помочь мне определить, в чем проблема?

Я задал предыдущий вопрос о том же проекте, но он был сформулирован ужасно, и редактирование могло вызвать больше путаницы, а не меньше.Кроме того, хотя на этот вопрос, возможно, и был дан ответ, мне еще многое предстоит выяснить.Это можно найти здесь

Ответы [ 2 ]

3 голосов
/ 22 августа 2011

Как минимум три вещи не так:

Во-первых, вы не суммируете по всем частотам в вашем IDFT. Это большая, большая проблема, в основном эквивалентная тому, чтобы брать только IDFT одной дискретной частоты вместо полных данных частотной области. Во-вторых, в вашем IDFT перевернут знак.

Измените строку 5 фрагмента 2 на

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

и убедитесь, что вы инициализируете doubleValue нулями.

В-третьих, вы захотите добавить шаг нормализации;

Изменить строку 7 фрагмента 2 на

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

В-четвертых, для вашего удобства протестируйте этот алгоритм с плавающей запятой, используя входы и выходы с плавающей запятой, прежде чем усекать до целочисленного типа данных, и не думайте, что вы получите точно правильные ответы, совершая циклический переход по интегральным данным. - ошибка с плавающей точкой очень реальна.

Это может также помочь захватить чужую реализацию DFT и IDFT и сравнить поведение с вашей реализацией на некоторых очень простых входных данных для обнаружения других ошибок. Поскольку ДПФ является линейной алгеброй, вы можете получить ее не совсем правильно и все же увидеть качественно хорошо выглядящие ответы.

1 голос
/ 23 августа 2011

В числовом смысле вы не можете этого сделать, поскольку ошибки округления и / или квантования почти всегда приводят к небольшим различиям или потере информации во время передачи туда и обратно.

Однако, если вы правильно и полностью внедрили DFT и IDFT, данные временной области могут быть воссозданы в рамках этой числовой ошибки. Возможно, что пара FFT / IFFT будет давать меньшие числовые ошибки, чем пара DFT / IDFT.

Если вы отбросите какие-либо термины (сложные мнимые термины или частотные интервалы или иное), результат будет дальше от оригинала. Например, если вашquency_domain_magnitude.length или freqUsed.length меньше длины данных, вы будете отбрасывать термины (если только вы не используете немного другой алгоритм и / или масштабные коэффициенты).

В вашей IDFT также есть как минимум 1 или 2 фатальные опечатки, как упоминает @ ellisbben.

...