0

私はこの方法を持っています:

public double sineWave(double t) 
{
   return amplitude==0?0:Math.sin(t * frequency * Math.PI*2 + phase) * amplitude;
}

別のクラスの別のメソッドによって呼び出され、単純な正弦波のサンプルが生成されます。このサンプルはバッファに追加され、サウンド カードに送信されます。t時間です。何らかの理由で、アプリケーションがこのメソッドを呼び出すほど、遅くなります。15 秒後には、CPU のコアをフルに使用して音声が途切れるほど遅くなります。

このコードであると 100% 確信しています。これを return 0 に置き換えると、実行にかかる時間 ( で測定System.nanotime()) が一定になるからです。

なぜこうなった?これを修正するためにできることはありますか?

4

4 に答える 4

5

ここの情報から-バッファの大きさは明確ではありませんが、反復ごとに t を増やしています。頻度が非常に高いと仮定すると、反復ごとに Sin() 引数を増やしています。引数が常に非常に高い値に増加しているかどうかを確認してください。簡単で汚いテストは、Sinのパフォーマンスが低下することを示しています -

public class SinTest {
  public static void main(String args[]) {
    long angle = Long.parseLong(args[0]);
    long startTime = System.nanoTime();
    for(long l=0L; l<=1000000L; l++) {
      Math.sin(angle);
    }
    long estimatedTime = System.nanoTime() - startTime;
    System.out.println(estimatedTime);
  }
}

$ java SinTest 100000
29181000
$ java SinTest 10000000
138598000
于 2013-01-13T21:21:35.807 に答える
0

ルックアップテーブルで問題を解決しました:

private static final int LUT_SIZE=1000000;
private static double[] sineLookupTable=new double[(int)(Math.PI*2*LUT_SIZE)];
static{
    for(double i=0;i<sineLookupTable.length;i++){
        sineLookupTable[(int)i]=Math.sin(i/(double)LUT_SIZE);
    }

}
private static double sinLUT(double t){
    return sineLookupTable[(int) (((long) Math.floor((t%Math.PI*2)*LUT_SIZE))%sineLookupTable.length)];
}
public double sineWave(double t) {
    return amplitude==0?0:sinLUT(t * frequency * Math.PI*2 + phase) * amplitude;
}

それは機能します...ちょっと、唯一の問題は、私が高周波で多くの歪みを得るということです。提案できる補間方法はありますか?

于 2013-01-14T07:44:19.487 に答える
0

ポイントを与えないでください。ソリューションには @mk の回答が与えられます。

public double sineWave(double t) 
{
    final double TAU = Math.PI *2;
    double a = t * frequency;
    a -= (long)a;
    return amplitude==0?0:Math.sin(a * TAU + phase) * amplitude;
}
于 2013-01-13T21:30:27.677 に答える
0

Math.sinJava フレームワークの現在のバージョンでは、値 ではなく、数学的に完全な値 2π を使用して引数を mod-reduce しようとしますMath.PI*2。あなたのようなコードの場合、これは、乗算で使用されたのと同じスケール係数 (つまり ) を使用して mod リダクションが実行された場合よりも、コードに時間がかかり、結果の精度が低下することを意味しますMath.PI*2。優れた精度と速度を得るには、次のようなものを使用して、乗算を行う前にモジュロ削減を実行する必要があります。

double thisSpin = t * frequency;
thisSpin -= (thisSpin - Math.Floor(thisSpin)) * 8.0; // value of 0-7.9999=one rotation
switch((int)(thisSpin*8.0))
{
  case 0: return  Math.sin(  thisSpin   * (Math.PI/4.0));
  case 1: return  Math.cos((2-thisSpin) * (Math.PI/4.0));
  case 2: return  Math.cos((thisSpin-2) * (Math.PI/4.0));
  case 3: return  Math.sin((4-thisSpin) * (Math.PI/4.0));
  case 4: return -Math.sin((thisSpin-4) * (Math.PI/4.0));
  case 5: return -Math.cos((6-thisSpin) * (Math.PI/4.0));
  case 6: return -Math.cos((thisSpin-6) * (Math.PI/4.0));
  case 7: return -Math.sin((8-thisSpin) * (Math.PI/4.0));
  default: return 0; // Shouldn't be possible, but thisSpin==8 would be congruent to 0
}

これにより、ドキュメンテーションによると、Java が低速で非生産的な範囲縮小の使用に切り替わるポイントである π/4 より大きい引数では、どちらsinも使用されないことが保証されます。cos

于 2014-06-07T17:43:00.327 に答える