整数計算でサインテーブルを生成する

これは、アセンブラ時代に、サインテーブルを生成する方法を色々試して、ある程度
成果のあった方法です。
※浮動小数点の sin で求めた値と微妙に違うところもありますが、実用性は十分あり
ます。

現在の C++11 以降では、constexpr でコンパイル時に計算して、定数としてソースコ
ードにテーブルを埋め込む事ができるので、必要性は薄いのですが、知っていれば、
応用範囲は広いでしょう。
ハードウェアーに実装して、周波数シンセサイザや音源の波形ベースに使う事も考え
られます。

x' = x・cos(s) - y・sin(s)
y' = x・sin(s) + y・cos(s)

s が十分小さい場合、以下のように近似できる。
cos(s) ≒ 1
sin(s) ≒ s

x' = x - y・s
y' = x'・s + y

テーブル生成に使っていますが、連続性がある場合は、リアルタイムに計算する事も
できます。(こちらの方が応用性があります)

非常に古いですが、1979年に発売された、ナムコのギャラクシアンで、編隊が、
実機の手前で、回転したり、サインカーブ的な軌跡で攻撃してくる場面がありますが、
この原理が使われていました。
※この当時、安易にテーブルにする人が多い中で、真のエンジニアでした。

また、単振動を使って、サインテーブルを計算する方法もあるかと思いますが、周期
を決定する定数を求めるのは、整数計算だけでは、簡単では無いと思えます。

テーブル生成では、テーブルのサイズは、2のN乗の方が、扱いやすいので、sの定
数を求める場合は、全円周(2・π)を、テーブル長で割る必要があります。

template <uint16_t shi, uint16_t len>
class sin_cos {

    static const uint32_t pai_ = 0xC90FDAA2;    ///< 円周率(3.141592654 * 2^30)
    static const uint32_t pai_shift_ = 30;      ///< 円周率、小数点位置

    uint16_t tbl_[(1 << shi) + 1];

    void build_()
    {
        int16_t gain = 16;  // 精度を確保する為の下駄
        int64_t x = len << gain;  // cos(0) の値
        int64_t y = 0;    // sin(0) の値
        for(uint16_t i = 0; i < ((1 << shi) + 1); ++i) {
            tbl_[i] = y >> gain;   // pai_ のビット位置補正
	    // 全周は、2・πなので+1
	    x -= (static_cast(pai_) * y) >> (pai_shift_ + shi + 1);
	    y += (static_cast(pai_) * x) >> (pai_shift_ + shi + 1);
        }
    }
    public:
        sin_cos() { build_(); }
};

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください