Как я могу перенести дискретный набор данных в частотную область и обратно (желательно без потерь) - PullRequest
1 голос
/ 29 июля 2011

Я хотел бы взять массив байтов размером примерно 70-80 КБ и преобразовать их из временной области в частотную (возможно, с использованием ДПФ). Я следил за вики и получил этот код до сих пор.

for (int k = 0; k < windows.length; k++) {
        double imag = 0.0;
        double real = 0.0;
        for (int n = 0; n < data.length; n++) {
            double val = (data[n])
                    * Math.exp(-2.0 * Math.PI * n * k / data.length)
                    / 128;
            imag += Math.cos(val);
            real += Math.sin(val);
        }
        windows[k] = Math.sqrt(imag * imag + real
                * real);
}

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

Вот код, который у меня есть для восстановления сигнала, который, я уверен, в большинстве своем неверен (предполагается, что он выполняет IDFT):

for (int n = 0; n < data.length; n++) {
        double imag = 0.0;
        double real = 0.0;
        sinValue[n] = 0;
        for (int k = 0; k < freqUsed.length; k++) {
            if (freqUsed[k]) {
                double val = (windows[k] * Math.exp(2.0 * Math.PI * n
                        * k / data.length));
                imag += Math.cos(val);
                real += Math.sin(val);
            }
        }
        sinValue[n] = imag* imag + real * real;
        sinValue[n] /= data.length;
        newData[n] = (byte) (127 * sinValue[n]);
}

freqUsed - логический массив, используемый для обозначения того, следует ли использовать частотное окно при восстановлении сигнала.

В любом случае, вот проблемы, которые возникают:

  1. Даже если используются все частотные окна, сигнал не восстанавливается. Это может быть связано с тем, что ...
  2. Иногда значение Math.exp () слишком велико и поэтому возвращает бесконечность. Это затрудняет получение точных расчетов.
  3. Хотя я следил за вики в качестве руководства, трудно сказать, значат ли мои данные. Это затрудняет тестирование и выявление проблем.

От руки от проблемы:

Я довольно новичок в этом и не до конца понимаю все. Таким образом, любая помощь или понимание приветствуется. Спасибо, что нашли время, чтобы прочитать все это, и заранее спасибо за любую помощь, которую вы можете предоставить. Любая помощь действительно была бы хорошей, даже если вы думаете, что я делаю это самым ужасным из возможных способов, я бы хотел знать. Еще раз спасибо.

-

EDIT:

Итак, я обновил свой код так:

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

для оригинального преобразования и:

for (int n = 0; n < data.length; n++) {
    double imag = 0.0;
    double real = 0.0;
    sinValue[n] = 0;
    for (int k = 0; k < freqUsed.length; k++) {
        if (freqUsed[k]) {
            double val = (2.0 * Math.PI * n
                    * k / data.length);
            imag += windows[k]*-Math.sin(val);
            real += windows[k]*Math.cos(val);
        }
    }
    sinValue[n] = Math.sqrt(imag* imag + real * real);
    sinValue[n] /= data.length;
    newData[n] = (byte) (Math.floor(sinValue[n]));
}

для обратного преобразования. Хотя я все еще обеспокоен тем, что это не совсем правильно работает Я сгенерировал массив, содержащий одну синусоидальную волну, и он не может даже разложить / восстановить это. Любое понимание того, что мне не хватает?

Ответы [ 2 ]

3 голосов
/ 29 июля 2011

Да, ваш код (как для DFT, так и для IDFT) не работает. Вы путаете вопрос о том, как использовать экспоненту. ДПФ можно записать как:

       N-1
X[k] = SUM { x[n] . exp(-j * 2 * pi * n * k / N) }
       n=0

, где j - квадрат (-1). Это может быть выражено как:

       N-1
X[k] = SUM {   (x_real[n] * cos(2*pi*n*k/N) + x_imag[n] * sin(2*pi*n*k/N))
       n=0  +j.(x_imag[n] * cos(2*pi*n*k/N) - x_real[n] * sin(2*pi*n*k/N)) }

, который, в свою очередь, можно разделить на:

            N-1
X_real[k] = SUM { x_real[n] * cos(2*pi*n*k/N) + x_imag[n] * sin(2*pi*n*k/N) }
            n=0

            N-1
X_imag[k] = SUM { x_imag[n] * cos(2*pi*n*k/N) - x_real[n] * sin(2*pi*n*k/N) }
            n=0

Если ваши входные данные только для реальных данных, это упрощается до:

            N-1
X_real[k] = SUM { x[n] * cos(2*pi*n*k/N) }
            n=0

            N-1
X_imag[k] = SUM { x[n] * -sin(2*pi*n*k/N) }
            n=0

Итак, в общем, вам не нужны ни exp, ни cos/sin.

1 голос
/ 31 июля 2011

Помимо правильных замечаний @Oli, у вас также есть фундаментальное недопонимание по поводу преобразования между временной и частотной областями. Ваш реальный входной сигнал становится комплексным сигналом в частотной области. Вы должны не принимать величину этого и преобразовывать обратно во временную область (это на самом деле даст вам автокорреляцию во временной области, если все сделано правильно, но это не то, что вы хотите). Если вы хотите иметь возможность восстановить сигнал временной области, то вы должны сохранить сигнал комплексной частотной области в том виде, как он есть (то есть отдельные реальные / мнимые компоненты), и выполнить комплексное преобразование IDFT, чтобы вернуться во временную область.

например. Ваше прямое преобразование должно выглядеть примерно так:

for (int k = 0; k < windows.length; k++) {
        double imag = 0.0;
        double real = 0.0;
        for (int n = 0; n < data.length; n++) {
            double val = (-2.0 * Math.PI * n * k / data.length);
            imag += data[n]*-Math.sin(val);
            real += data[n]*Math.cos(val);
        }
        windows[k].real = real;
        windows[k].imag = image;
}

где windows определяется как массив комплексных значений.

...