LabVIEW で P2P ストリーミングを簡単に実現

ソフトウェア無線機を構築する方法の一つとして PXIe モジュールを組み合わせた方法があります。
例えば、RFSA(受信機・スペアナ機能)とRFSG(送信機・SG機能)の PXIe ハードウェアを使って、信号処理はソフトウェアでする場合であったり、RFSA、RFSG ハードウェアと FPGA モジュールを組み合わせた方法です。
今回は、このデバイス間でのデータ転送方法である P2P ストリーミングが LabVIEW で簡単に構築できるということについて解説します。

●P2P ストリーミングとは?

あるハードウェアモジュールから別のハードウェアモジュールに対して、CPU を介さずに直接データ転送する方法として P2P(Peer-to-Peer) ストリーミング転送 があります。
例えば、
・RFSA(受信機・スペアナ機能)で受信した信号をRFSG(送信機・SG機能)へ直接転送して送信する
・FlexRIO (FPGAモジュール) でリアルタイム変調した信号を RFSG に直接転送して送信する
・RFSA で受信した信号を FlexRIO に直接転送してリアルタイム復調する
といった用途で使用できます。
このメリットは、直接デバイス間でデータを転送するため、CPU に負荷をかけることがないことです。逆に言うと、直接デバイス間でのデータ転送をしない場合には、一度 CPU 側のメモリにデータを蓄積して、別のデバイスにそのメモリ上のデータを渡す必要があり、CPU負荷、メモリ負荷が発生します。
National Instruments 社に詳しい説明があります。こちらも参考にしてみてください。
ピアツーピアストリーミングの概要 <http://www.ni.com/white-paper/10801/ja/>
clip_image001
P2P ストリーミングでは CPU を使わずにデータを転送できる。

●LabVIEW なら簡単に P2P を実現

LabVIEW で P2P ストリーミング機能を使うときには NI-P2P ドライバを使うことになります。
上述「ピアツーピアストリーミングの概要」にも書いてありますが、LabVIEW のNI-P2P ドライバを使うと劇的に簡素化されます。
まず、ハードウェア側には FIFO ベースの P2P ライタ、P2P リーダというものがあります。
上図の FlexRIO (FPGA) はデータを送る側なので P2P ライタの FIFOがあり、RF-SG はデータを受け取る側なので P2P リーダの FIFO があります。この 2つの FIFO 間でデータを直接転送します。
ハードウェアだけでは、P2P の FIFO があるだけで、それだけでは転送できません。データの送り元である P2P ライタとデータ受け取り側である P2P リーダの関係付けをホストでしてあげる必要があります。
といっても、ホスト側のプログラミングは簡単です。
・P2P ストリームの初期化・ひも付け
・必要があればループを作ってそこで P2P のステータス監視
・終了時に P2P ストリームのフラッシュと停止
とこれだけです。
clip_image002
初期化時に NI-P2P ドライバの関数「niP2P Create Peer to Peer Stream.vi」を使って、P2P ライタと P2Pリーダのひも付けをします。デフォルトならこの関数で P2P 転送の準備が完了します。あとは勝手にハードウェア側で、P2P ライタにデータが入れば自動的に対応する P2P リーダにデータが転送されます。
clip_image003
これは必要があればですが、P2P ストリームの転送状態もプロパティノードで簡単に見ることができます。例えば、転送状態モニタ用の While ループを作成し、そのなかで P2P ライタ FIFO のオーバーフローや、P2P リーダ FIFO のアンダーフローなどを確認できます。
clip_image004
終了したいときは、「niP2P Flush And Disable Peer to Peer Stream.vi」と「niP2P Destroy Peer to Peer Stream.vi」を使います。
このように煩わしい設定はほとんど無く、P2P ストリーミングを使用することができます。

●P2P 送信側と受信側のレートについて

P2P転送の転送単位は、サンプル数になります。
例えば、送信側受信側双方に100MS(メガサンプル)とした場合、
・送信側は100MSのレートで送り出す必要がある
・受信側は100MSのレートで受け取る必要がある
となります。

このように送受双方が同じレートの場合は、送信側受信側双方共がデータの破たん(オーバーフローやアンダーフロー)が発生しないようにしなければなりません。
送信側FPGAは常に100MSでデータを送り出す必要がありますし、受信側も常に100MSでデータを受信し続ける必要があります。

ちなみに送受双方のデバイスの動作クロックが非同期の場合、送受信のタイミングが微妙にずれてデータの破綻が発生する場合があります。
このような場合は、P2P 送信側のデバイスのリファレンスクロック、 P2P 受信側のデバイスのリファレンスクロックを同じクロックソースから与えてサンプリングタイミングを同じにする必要があります。

翻って、送信側FPGAの動作レートが高速で200MSで送信可能な場合は、受信側の100MSの倍の動作が可能ですから、送信側FPGAは送受信に使用するFIFOの状態を見て、送信するかしないか調整することが可能です。
つまり送信側FPGAは動作に余裕があるので、送信待ちの間に「受信した信号にフィルタ処理を行う」など他の処理を行うことが可能になるのです。

実際にドルフィンシステムでFPGAを実装する場合は、必要なレートをまず割り出してから「どの合間で信号処理を実装するか?」などを検討して設計を行っています。

●データタイプが異なる場合でも転送方法を自動で対応してくれるようです

また、P2P ライタと、P2Pリーダのデータタイプが同じでない場合でも以下の様な場合は自動で認識して分割転送してくれるようです。
P2P ライタが U64 (64bit データ) で P2P リーダが U32 (32bitデータ) の時、U64 データは 上位 U32、下位 U32 の順で転送されるようです。これは特に指示することなく自動的にやってくれます。
上位、下位の順で転送されるため、P2P ライタ側の書き込みレートは P2P リーダ側の読み出しレートの半分で良いことになります。
FPGA で実装している場合、動作クロックレートを半分にできるということは、コンパイルする際に有利に働きます。たとえば 200MHz で U32 データを転送する場合、データ転送レートは 200M * 4 Byte = 800MB/s です。このレートと同じレート維持したまま、U64 で書き込むには 100MHz のクロックレートで良いことになります。
当然、100MHz のクロックでコンパイルをしたほうが、タイミング違反によるコンパイルエラーが出にくくなります。(使用リソースは並列度があがるので比例して増えますが)
このようにデータタイプが異なっても特に指示をせずに自動で転送をしてくれるので便利です。ただ、どのように転送されるかはどこかで確認できるわけではなさそうなので、やってみて確認しておいた方が良いようです。











































0 件のコメント :

コメントを投稿