VNA製作について、前回のハードウェア編に引き続いて、GNURadioによる信号処理編です。
目的の反射信号とリファレンス信号は、フロントエンドによりLow-IFの低周波信号に変換されていますので、これをサウンドカードで取り込みます。取り込んだ信号はGNURadioで処理します。まずはgnuradio-companionで、目的の信号が取り出せるかどうかを試してみます。
以下のようなフローグラフを構築してみました。取り込んだ信号を狭帯域のBPFでIF信号を取り出し、スペクトルをFFTで観察してみます。発生させる信号については、GNURadioとは別に、前回のスクリプトでを実行して周波数を設定します。発生させている信号は100MHz、IF周波数としてとりあえず5kHzにしてみました。(クリックで拡大)
これを動作させてみたところ、FFTは以下のような二つのスペクトルが得られました。BPFで実信号が複素信号に変換されていますが、FFTの表示で正の成分のみが残っていることがわかります。TXポートにはオープン、すなわち全反射状態ですので、反射信号はこれが最大値です。サウンドカードの入力ゲインが調整できるのであれば、飽和しない程度に調整しておきます。
これの振幅と位相差を計算するために、フローグラフを以下のようにしてみました。振幅は複素信号のmagを取って対数に変換、位相差は反射信号を参照信号で割り算して角度に変換し、-90度~90度の範囲で数値を表示するようにしてみました。(クリックで拡大)
TXポートがオープン状態だとこのようになります。Reflectの信号が大きいことに注目。
次に、TXポートに50Ωのロードを接続してみます。
そうすると反射信号(Reflect)の振幅が減ります。
反射と終端がちゃんと信号の振幅変化に反映されているようですので、それっぽく動作しているようです。
さて、単一の周波数での反射信号の変化が見えたので、今度は周波数を変化させてグラフ化してみます。DDSの周波数コントロールと、測定値の取得をpythonスクリプトで行います。
gnuradio-companionで作成したフローグラフを実行する際には、実行時にpythonスクリプトが生成され、そのスクリプトが別プロセスで実行されています。このスクリプトを読むと信号の流れがコードでどのように実現されているのかがわかります。pythonスクリプトを直接修正して動作を変更したり、機能を追加することも可能です。このスクリプトをベースに、周波数をスイープするように改造してみます。
生成されたpythonスクリプトを見てみると、各ブロックのインスタンスを生成して、それを接続するようになっています。そのあたりはそのまま使うことにします。主な改造ポイントは、GUI関係の機能を外し、DDSの初期化と周波数設定のコードを追加、ループでそれをスイープするようにして、ステップ周波数毎に、位相差、信号振幅の計測値を、周波数と共に標準出力に書き出すようにしました。Probe Signalブロックを使用することで、グラフ中を流れるデータを数値として取り出すことができます。信号処理と周波数スイープが並行して動作するよう前者をスレッド化しています。グラフ化は、得られた標準出力をテキストファイルに落として、それをgnuplotで読み込んで表示するようにします。
コードは末尾にあるgistへのリンクを参照してください。vna_prove.pyを実行すると以下のような出力が得られます。
$ ./vna\_probe.py -s 1e6 -e 197e6
Using Volk machine: sse4\_1\_64\_orc
>>> gr\_fir\_fcc: using SSE
1000000 -0.086028 -0.891152 2.548056
5000000 0.121880 -0.852427 2.556522
9000000 0.362316 -0.702829 2.559791
13000000 0.633015 -0.696128 2.562027
17000000 0.878260 -0.670300 2.565089
...
193000000 2.406580 0.180699 2.550249
197000000 2.428711 0.191352 2.546565
余分なゴミが出ますが、これを取り除いてgnuplotでプロットします。とりあえずシェルスクリプトvnaplotで行うようにしました。グラフはPDFで出力するようにしています。
$ ./vnaplot -s 1e6 -e 197e6
周波数スイープしてプロットした結果は以下のようになります。グリーンのラインが反射信号です。赤線が位相差で角度はラジアン表示(-π〜π)としています。青線は参照信号の振幅で、参考のため表示しています。
TXポート・オープン
TXポート・ロード
ロードとオープンで反射信号の差が30dBから20dB程度ありますので、それっぽい結果が得られているようです。欲を言えば、ロードとオープンの信号の差は、もう少し大きくなって欲しいところです。周波数が上がるに従いロード状態でもすこしずつ反射信号が増えています。これはブリッジが、分布定数や非対称な構造により不完全である、もしくはロードの抵抗値がブリッジと合っていないことが原因だと考えられます。残念ながらあまり良いブリッジになっていないようです。
試しに60cm程度の同軸ケーブルを先端オープンのままTXポートに接続してみます。TXポートオープンと比べて、全反射であることには変わりはありませんが、位相(赤線)がぐるっと回っていることがわかります。
信号の振幅と角度が得られているので、これを極座標にプロットするとスミスチャートっぽくなるはずです。それはまたの機会に試みたいと思います。
ノウハウと問題点をメモしておきます。
周波数スイープは、範囲を50ステップに分割して、順次周波数を切り替えながら、計測値を取得しています。このステップ毎に100ms程度の待ち時間を入れています。50ステップの計測で全体で7秒程度要しています。
計測の高速化のためには待ち時間を少なくする必要がありますが、あまり短くするとスムースな結果が得られません。実験してみたところ70ms以上は必要なようです。DDSは即座に周波数の変更が反映されているはずですので、他にこのような遅れが生じる原因としてはBPFやprobeで生じているのかもしれません。これはフローグラフの工夫や、コンポーネントを改善することが必要かもしれません。VNWAではステップ毎に1ms程度と非常に高速に計測できているようですので、研究してみたいところです。原理的にはLow-IF 5kHzの一周期は0.2ms、アベレージングを考えてもその10数倍と考えれば、msオーダーでの計測が可能なはずです。
上で示したグラフは0〜200MHzと書きましたが、実際には1MHz〜197MHzを50分割でプロットしています。0〜200MHzでプロットすると以下のようなグラフになってしまいます。
40MHzの整数倍の周波数で乱れが生じています。DDSのクロック周波数と整数比になるような周波数ではスプリアスのスペクトルに重なりが生じてしまい、スムースな測定結果にならないようです。これを回避するために、とりあえずスイープ周波数を若干ずらしてグラフ化しています。
電源ノイズ
USBを電源としていますが、ノイズ除去の工夫をしなかったために、予想以上にノイズが乗ってしまいました。BPFを通さない場合のFFT画面を下記に示します。
これをBPFに通すとこんな感じでまるで信号があるように見えてしまいます。
ノイズレベルが高いことで、ダイナミックレンジが制限されてしまっています。別電源とすることでノイズは殆ど無くなりますが、煩雑になるのでできれば別電源とすることは避けたいと考えています。電源周りになにかしらの追加対策が必要だと考えています。
長くなったので今回はここまでにします。次回は周波数レンジの拡大すべくサブナイキストでの動作について書く予定です。
使用したコード
- vna_probe.py フローグラフから改造したpythonスクリプト。ステップ毎に周波数と反射信号振幅、参照信号振幅、位相差を標準出力に出力する。コマンドライン引数で周波数範囲やスイープ分割数を設定する。pylibftdi.py vna.py dds.pyが必要です。 https://gist.github.com/edy555/5057481#file-vna_probe-py
- シェルスクリプトvnaplot 上記を実行した結果をファイルに落としgnuplotでグラフ化している。Mac OSXなのでgnuplotがちょっと変なパスにある。gnuradioが出す余分な出力をsedで削除している。https://gist.github.com/edy555/5057481#file-vnaplot
- フローグラフ(FFTのみ) https://github.com/edy555/gnuradio-trial/blob/master/vna-fft.grc
- フローグラフ(magarg付き) https://github.com/edy555/gnuradio-trial/blob/master/vna-magang.grc