1

おおよそ70〜80kのサイズのバイト配列を取得し、それらを時間領域から周波数領域に変換したいと思います(おそらくDFTを使用)。私はwikiをフォローしており、これまでのところこのコードを取得しています。

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. ガイドとして wiki に従っていますが、私のデータが意味があるかどうかを判断するのは困難です。これにより、問題のテストと特定が困難になります。

問題から離れて:

私はこれにかなり慣れていないので、すべてを完全には理解していません。したがって、任意のヘルプまたは洞察をいただければ幸いです。時間を割いてすべてをお読みいただき、ありがとうございます。また、ご提供いただけるご支援に感謝いたします。私がこれを可能な限り最悪の方法で行っていると思われるとしても、どんな助けも本当に良いです. 再度、感謝します。

-

編集:

そこで、コードを次のように更新しました。

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

逆変換用。私はまだそれが正しく機能していないことを心配していますが。単一の正弦波を保持する配列を生成しましたが、それを分解/再構築することさえできません。私が欠けているものについての洞察はありますか?

4

2 に答える 2

3

はい、コード (DFT と IDFT の両方) が壊れています。指数関数の使用方法の問題を混乱させています。DFT は次のように記述できます。

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

ここjで、sqrt(-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

于 2011-07-29T16:36:23.777 に答える
1

@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;
}

wherewindowsは複素数値の配列として定義されます。

于 2011-07-31T08:35:08.813 に答える