2012年10月27日土曜日

DFT IPの作成

AC97 Codec用のコントローラは大体出来たので、次にオーディオ帯域用のスペクトルアナライザを作って見たくなった。スペクトルアナライザと言えば、おそらくFFT方式が常套手段だと思うが、今回はDFT (Discrete Fourier Transformation)方式でやってみることにした。

DFTの式と言えば、教科書等には大体以下のような式が記述されていると思う。
この式は一つの周波数に関しての式になっており、全体的なスペクトルを求める形式にすると以下のようになると思う。
ここで、信号Xnについて、信号は-∞から+∞へ連続している信号列と定義し直す。
つまり、
そして、(1)式を、任意のp点からp+(N-1)までの区間の信号列に対して行うように書き直す。

また、今回はスペクトルアナライザを作成するので、p~p+(N-1)の区間の次は、p+1~p+(N-1)+1、…と連続して変換していきたい。

この(4)式はS(f,p) を使うと以下のように書ける。

ここで、

なので、結局、

となる。。。。 うほっ、、、これは面白い。!!
この式は、直前のスペクトル値を用いて回帰的に計算すれば、exp(2πf/N)の乗算だけで済むことを表している。乗算・加減算の回数も(1)式に比べてかなり少なくなる。

ここまでの式では、p点からp+(N-1)までの信号を用いて、p点のスペクトルを計算するという表現になっていたが、これだと未来の信号を用いて現在の値を求めるような形になり、少々気持ち悪い。
そこで、過去のN点から現在の値を求める形式に書き直す。

これを、実数部と虚数部に展開してまとめると以下のようになる。

(1)式の場合、乗算は2N回、加算が2(N-1)回だが、上記式の場合、乗算4回、加減算が6回だ。

念のため、C言語のプログラムを作成してシミュレーションしてみた。
プログラムは以下のとおり。

32~41行で入力信号を作成している。以下に波形を示す。

0~1024の区間はx1、x128倍、x256倍の周波数の合成波で、2048~3062の区間はx64倍の周波数の信号だ。従って、処理の初めのほうでは、スペクトルはx1,x128,x256の3箇所で観測され、次にx64で観測され、最終的にはスペクトルは観測されなくなる筈だ。
上記プログラムの出力から、各サンプル毎のスペクトルをgnuplotで描画・出力し、avidemuxでこれらを合成して、動画を作成した。このアルゴリズムをFPGAに実装して、上記のような信号列を入れれば以下のようなスペクトル波形が得られるはずだ。


うほほっ、、、面白い。 ちゃんと周波数領域に変換できている。
この方式だと、コンパクトな回路が出来そうだ。
使用周波数帯は、オーディオ帯域用を考えているが、これに対してFPGA内部が100MHzでの動作となるので、例えばオーディオのサンプリングレートが48KHzの場合速度比は2083倍になるので、1サンプル毎に2048点程度のDFTは楽勝で出来そうだ。

スペクトル全体を求める式は(2)式風に書くと、以下のように書ける。

ここで、正弦波形の対称性を考慮すると、

なので、(9)式は以下のようにも出来る。


つまり、exp(2πf/N)部は1/4象限分のみ持てばよくて、かつ、演算部を4並列することで、1サンプル以内の点数を4倍に増やせる。したがって、回路規模は若干大きくなるがこの方法でやれば8192点程度は出来そうだ。

それでは、RTL作成に進もう。

2012年10月14日日曜日

AC'97 Codecを制御してみる 4

DRAMコントローラとクライアントモジュールとのI/FはMPIFという独自I/Fになっており、これは通常のREAD,WRITEコマンドの他にFILLとSWAPコマンドがある。


SWAPは同一アドレスへのREADとWRITEをアトミックに実行できるコマンドで、マルチCPU構成時のMutex制御(排他制御)等での使用を想定して設けたコマンドだが、それ以外にも使用できそうだ。

今作成中のDMACはREADを使っているが、SWAPを使うようにすればDMAバッファをリードした後にゼロクリアしたり、あるいは、マイクやLINE IN等の録音データで置き換えることができる。
バッファをcirculationモード、即ちリングバッファとして使用すれば、録音データの遅延再生機能を実現できる。LM4550は下図に示すとおり入力データをDACデータと合成して出力する機能もあるので、この機能と合わせるとリバーブレータ(残響効果器)のようなことができそうだ。



レジスタ仕様は以下のように変更した。


以下はシミュレーションの様子 (clear_to_zero 選択時)


replace_to_ADC_data モードで、遅延が250uS, 10mS, 100mS, 500mSになるようにして、動かしてみた。

250uS

10mS


100mS


500mS



2012年10月9日火曜日

AC'97 Codecを制御してみる 3

AC'97 Codec用の制御回路を作成して、信号を出したり音楽データを再生させることはできた。
元々はCodecをDACやADCとして使ってみようと考えていたのだが、意外と出力のノイズが目立つので方針を変更して、本来のAC'97用コントローラの形にまとめてみることにした。

以下にブロック図を示す。


このコントローラは3つのブロックで構成される。 CodecへのPCMデータの出力はDMAによる方法とCPUによるレジスタへの書き込みによる方法を選べる。
DMAの場合、DRAM上にバッファ領域を確保しそのアドレスをレジスタに設定する。


DMACにはバッファの使い方で2つのモードを持たせた。1つはBEGINからENDまで転送したら動作完了となる non-circulation モードで、もう1つはENDに達したらBEGINから再び転送を行う circulation モードである。 前回の実験では音楽データ1曲分をDRAMに展開して再生させたが、これだと非常に大きなメモリ空間を占有してしまうことになる。 音楽データ全体はフラッシュメモリや外部記憶上にあり、そこから少しずつDRAM上のバッファに転送して出力するというやり方が一般的だろうと思う。  ただし、この場合はソフトウェアの介在が不可欠で、DMACのバッファからの読出しに同期してバッファのデータを更新する必要がある。このコントローラの場合は、DMACのポインタがTHRESHOLDレジスタで示すアドレスを通過したタイミングと、ENDレジスタで示すアドレスを通過したタイミングで割込みを発生できる。THRESHOLD通過割込みが発生した場合、BEGINからTHRESHOLD間のデータは転送済みなので、ソフトウェアはその領域を次のデータで更新する。同様にして、END通過割込みではTHRESHOLDからEND間のデータを更新する。もちろんこの方法の場合はDMACをcirculationモードで使用する。

全体的な外部仕様(レジスタ仕様)は以下のとおりだ。




自作CPUで遊ぶ 25

まだ制御ソフトが完成していないので今まではスピンドルを移動するために一々簡単なプログラムを書いて移動させていたのだが、非常に面倒なのでCNCペンダント的なものを作ることにした。 右側の縦に2つ並んでいるスイッチ...