C で正弦波の振幅 (1 から -1 で表される) を含む任意の長さの符号付き float 配列を生成する最も効率的な方法は何ですか?
3 に答える
非常に高速なものが必要な場合は、テーブルを使用します (既に提案されているように)。
もう 1 つのアプローチは、小さな正弦波発振器をシミュレートし、それを使用してデータ配列を生成することです。
これを行う方法の例を次に示します。
int main (int argc, char **args)
{
int i;
float data[1024];
float angle = 2.0f * 3.14 / 1024;
// start of the sine-wave:
float sinval = 0;
float cosval = 1;
// rotation per iteration
float delta_sin = sinf(angle);
float delta_cos = cosf(angle);
for (i=0; i<1024; i++)
{
// store current value:
data[i] = sinval;
// update the oscillator:
float s = sinval * delta_cos - cosval * delta_sin;
float c = sinval * delta_sin + cosval * delta_cos;
sinval = s;
cosval = c;
}
}
この背後にあるトリックは、9sinval、cosval に格納されている 2D 空間の固定点から開始することです)。さらに、(delta_cos、delta_sin) で 1 回の回転のパラメーターを事前計算します。
ループ内で行うことは、ポイントを固定回転で 1024 回回転させることだけです。これにより、反復ごとに sin/cos ペアが作成されます。(注: 複素数の乗算と同じです)。
このメソッドは遅かれ早かれ不安定になり、ループ内で sin/cos を呼び出すほど正確ではありません。
したがって、それを使用して巨大なテーブルを作成することはお勧めできませんが、わずかなエラーと最大 1 万要素までの小さなテーブルに耐えることができれば、非常に使用可能です。この問題を回避するには、型を double に変更するか、適切な丸めを行うか、n 反復ごとに結果を再正規化します。
編集: double と 1e9 の繰り返しでコードをテストしました。私のために働きます。位相にわずかなドリフトがありますが、結果は単精度の sinf/cosf を使用するよりも正確です。
Carl Smotricz が彼の回答で指摘したように、ハードコードされた配列を作成する単純な C プログラムを簡単に作成できます。
次のコードはトリックを行います:
int main(int argc, char * argv[])
{
const int tableSize = 10;
const char * fileName = "sin_table.txt";
int x;
FILE * file;
file = fopen(fileName, "w");
if (file == NULL) { printf("unable to open file\n"); return -1; }
fprintf(file, "float sin_table[%d] =\n{\n ", tableSize);
for (x = 0; x < tableSize; x++)
{
fprintf(file, "\t%f,\n", sinf(x*2*pi/tableSize));
}
fprintf(file, "};\n");
fclose(file);
return 0;
}
出力は次のようになります。
float sin_table[10] =
{
0.000000,
0.587785,
0.951057,
0.951056,
0.587785,
-0.000000,
-0.587785,
-0.951057,
-0.951056,
-0.587785,
};
実行時のオーバーヘッドが必要ない場合は、すべての値を C 配列の宣言/初期化として出力し、#include
そのファイルをプログラムに出力する小さなプログラムを自分で作成します。