PCでのDDS

だいぶ前のエントリなので気がひけますが、JI3GAB*1のブログより。発振器として使っている正弦波生成プログラムが破綻するという話題。

朝方にはなんとか動いて気分良く寝たのですが、夕方3.5MHzをワッチしていると最初はいいのですが、数十分くらいするとだんだん出力が大きくなってきて、しまいにはサチってしまうことに気づきました。変更したのは局発のところだけなので、きっと正弦波の振幅が誤差の蓄積で大きくなっているのだろうなと思って調べてみたら、やはりそのようです。

SIN/COS同時生成を利用して、サンプル毎にω分だけ回転させるアルゴリズムを利用されています。おそらく計算時間の短縮を狙ってのことだと思います。
演算が破綻したのは加算時の丸め誤差が原因です。浮動小数点数は乗算時はほとんど誤差が出ません*2が、加算時には盛大に誤差が発生します*3。長時間の運用でおかしくなったのは不思議ではありません。倍精度化で実用時間内では問題はなくなると思いますが、問題が解消したわけではないので気持ち悪さは残ります。
実用的にはDDSと同じくωのみ累積で更新していき、都度SIN/COSを計算するのが無難です。テーブル・ルックアップでSIN/COSを計算する場合には、三角関数の公式を利用して表のサイズを小さくする事ができます。私のプログラムは表を2分しましたが、3分することもできます。
一方、SIN/COS関数を直接計算する場合は、素直にライブラリ関数を使うほうが効率が上がると思われます。この場合、コンパイラはFPUの三角関数命令を直接使うはずですから、自分で多項式近似をするより速いプログラムになるでしょう。
iA32の場合、何しろ処理能力が高いです。48Kサンプルでも余裕で正弦波を生成できるはずですのでライブラリ関数で済ますのが一番だと考えます。

*1:CQ誌ではコールサインは敬称略だったが、ブログの場合はどうなんだろう。

*2:出ノーマルを除くと仮数部±0.5LSB

*3:2数の絶対値が大きく異なる場合