2011年12月17日土曜日

FUNCTION GENERATORの作成 1

ファンクションジェネレータはケースに入れて末永く使える物にしたいと思っており、その為にはFPGAも評価ボードではなく専用の物が欲しくなる。が、あんまりお金もかけられないのでFPGA部についてはSDR-SDRAMC作成で使用したSpartan3EのボードかLattice XP2のボードを利用しようと考えている。 でも、それにインプリするのはまだ先の話だ。 Spartan3A StarterKitはDACも搭載されているので、これを使って開発を行う。 それで今は正弦波発生部(DDS)の検討を行っている。正弦波はsin(n)のテーブルをROMに持っておき、ROMのアドレスを0から順次与えてROMのリードデータをDACに出力する。

正弦波テーブルはROMなのでnは角度値そのものではなくテーブルの要素番号になる。つまり、1周期をN分割してテーブルに持つ訳であり、1アドレスは2π/Nの角度に相当する。ROMにアドレスnを入れて出力を得るということはsin(n・2π/N)の値を得ていることになり、nを0からN-1まで1づつ増加させて得られる正弦波を基本波とすると、nをm倍の速度で増加させれば(n += m)、m倍の周波数の波形が得られることになる。でもこれだと基本波の整数倍の周波数しか得られない。1.2倍とか2.5倍等小数倍の周波数を発生させたい場合は何らかの補間処理が必要になる。この補間方法として直線補間または4点のラグランジェ補間を考えていた。

ラグランジェ補間は上記のような演算を行う。割り算があるが分母の各項は何れも既知なので定数化できる。また、乗算等の演算量も多い。 以下はN=360でnを0.1刻みにした時の直線補間とラグランジェ補間の比較だ。 何bitのDACを使うかは未定だがとりあえず16bitDACを使うという想定で、正弦波の最大振幅は32767にしている。波形は両者差が無いように見える。

以下は理想値に対する誤差だ。

これを見ると直線補間の方は最大1.3 digit程度の誤差が発生するのに対してラグランジェ補間の方はほぼ0となっている。ところが、上記の計算では振幅の量子化(小数点以下の切り捨て)をしていなかった。量子化した場合は以下のようになった。

これをみると、ラグランジェ補間の方も最大1digitの誤差があり、直線補間と大差なさそうなので直線補間で行くことにした。 次に1周期の分割数Nは幾つがいいか?  小さいと直線補間での誤差が大きくなり、大きいとテーブルサイズが大きくなってしまう。 Nを上図の10倍の3600とし、DACのサンプリング周期を1usとした場合、目標仕様の下限周波数1Hzを作るためにはnは1us x 3600 = 0.0036刻みにしなければならない。 駆動周波数にもよるとは思うが(たぶん)float adderはlatencyが1以上かかるので、phase accumulator部は固定小数演算にしたい。その場合、固定小数の小数部が何ビットあれば0.0036を十分に近似できるだろうか? 整数部は分割数N、つまり3600が表現できる必要があるので12bit必要で、phase accumulatorが32bitの場合小数部は32-12=20bit、この20bitで0.0036を近似すると0.003599・・ (99.977[%])と%オーダーの誤差になる。 FPGAに入力される源振(水晶発振器)の周波数精度はppmオーダーなので、%オーダーではちょっと残念だ。 せめて整数Hz(1Hzの整数倍)は精度よく出したい。 そこで分割数Nは1000000(20bit)、小数部を12bitにしようと思う。 この場合、テーブルサイズがめちゃめちゃデカくなってしまう。正弦波は相似形な波形なので1/4象限のデータのみをテーブルにして他はそれを写像して作り出すことはできる。そうするとテーブルサイズは1/4の250000になる。振幅の最大値を32767にするのでデータのbit幅は15bit、したがってそのままでは250000 x 15 = 3750000、 3.5Mbitの容量のROMが必要になってしまうが、以下の方法で圧縮できるはずだ。 250000を例えば4要素毎の区間に分割し区間内では先頭のみ15bitデータ、他は前方の要素との差分とする。

sin関数は0の部分が最も変化率が大きいが、今検討している分割数の場合その部分の変化率(差分)は1以下なので差分は1bitで表すことができる。ということは4要素の場合15bit x 4 = 60bitが18bitと1/3に圧縮できる。要素数を増やせばさらに圧縮率は高くできる。また、この方式は直線補間をする上でも都合がいい。 直線補間は以下のような演算になるが、Δy10は差分値がそのまま使える。 Δx10は要素nとn+1の差なので1、(x-x0)はphase accumulatorの小数部になる。したがって、差分値が1か0かでy0に小数部を加算する・しないを行えば良い筈だが、テーブルのデータが既に15bitに量子化されていてかつ出力するDACも16bitだとすれば、小数部をそのまま加算する意味は無いので、実際は小数部を四捨五入して加算するようにする。

テーブル1要素のデータ構成、即ち、何要素でグルーピングするのがいいかについて検討する。
上記では4要素の図を示したが、実際は直線補間のためにもう1要素(例えばP0~P3とP4)必要になる。要素数に対する圧縮率とROM容量を計算すると以下のようになった。

要素数30位から飽和している感じで、要素数32の場合ROM容量はおよそ370Kbitだ。冒頭に書いたようにターゲットFPGAはSpartan3E(XC3S250E)またはLatticeのXP2(XP2-5)であり、これらのBlockRAMの容量は250Eが216K、XP2-5が166K、・・・・・うぅぅ、はいらねーーー、くそー もうひと工夫必要だ。
テーブルに書くデータをCプログラムを書いて生成してみた。右側8桁が差分情報だ。

ここで差分データからuniqなデータ数を数えてみたら734個だった。

そこで差分データのuniqなパターンに固有番号を付与してテーブルにはその番号を書くようにすれば、32bitのデータが(734個なので)10bitになる。したがってROM容量は(15bit+10bit) x 7813 word = 195.325KbitになるのでXC3S250Eにはギリギリ入りそうな感じだ。伸張処理では番号をビットデータに戻すためのテーブルが必要になるがこれは分散RAMで作るしか無いだろう。分散RAMは38Kbitあり、必要な容量は734x32bit = 23.488Kbitなので入るんじゃなかろうか?  厳しいかなー??? ・・・待てよ! MicroBoardを使う手があるぞ。あれならSpartan6 LX9でEBRは576Kbit, 分散RAMは90Kbitなので余裕のよっちゃんだ。おー、250EでダメだったらMicroBoardにしよっと。

0 件のコメント:

コメントを投稿

自作CPUで遊ぶ 22

今使用しているモータードライバはDM556Dというものだが、このドライバはMicro Stepが 800 [pulse/rev] 〜 40000 [pulse/rev]の範囲で設定できる。 Mi...