Computer & RF Technology

NanoVNAの信号から反射係数を計算し周波数特性をプロットする

ベクトルネットワークアナライザNanoVNAの実験の続きです。ネットワークアナライザでは、発生したRF信号に対する被測定物(DUT)の応答を、振幅と位相で計測するのですが、結果は反射係数として複素数で得られます。反射係数を波形の信号から求めるのが今回の目的です。反射係数が得られるようになったら、周波数をスキャンさせながらこれを実行することで、周波数特性が得られることになります。プロットすると見慣れたグラフが得られるはずです。

image

前回こんな波形を取得できていました。ブリッジから得られた信号をミキサーでIFに変換し、オーディオコーデックでサンプリングしたものです。緑が基準となる参照波、青が測定対象の反射波です。コーデックで48kHz, 16bitステレオ2chに変換され、その信号の5ms分240サンプルをプロットしたものです。

image

反射係数を求めるとは、参照波の位相を基準として、目的信号の位相と振幅を計算することになります。見た目は面倒そうですが、Pythonで実装してみると、驚くほど程簡単にできてしまいました。これを理解できると便利だと思いますので、少し解説します。

まずは5msのステレオの信号を、長さ240の二つの配列に分けます。それぞれをref, sampとします。これらをそのままプロットしたものが上の波形です。ほぼ5kHzのみのスペクトラムとなっています。中身は符号付き16ビット整数で、こんな感じです。

image

このうち、refをヒルベルト変換します。すなわち90度位相のずれた信号を作るのですが、実はscipy.signal.hilbertという関数がscipy.signalに用意されています。この関数に与えるだけでいきなり複素化してくれます。結果の実部と虚部をプロットすると以下のようなグラフが得られます。90度ずれているのがわかります。(わかりやすいよう48サンプルのみ表示しています)

image

この複素化した参照波refhについて、目的の信号波sampとの相関(内積)を取ります。相関を取るとは、二つの信号それぞれのサンプルを乗じて、全部を加算する操作になります。二つの正弦波の相関を取ると、同じ周波数であれば、同位相なら最大、逆位相で最小、90度ずれていれば0、位相がずれていれば位相ズレに応じた値となります。この処理を、参照波refの正弦と余弦それぞれについて、信号波sampに対して行うのですが、参照波は既に正弦と余弦が実部虚部の複素数になっていますので、複素化された参照波を、実数である信号波に単に乗じて全加算するだけで、複素反射係数が得られます。

式にすると下記となりました。ヒルベルト変換を含めてたった2行で書けます。numpy/scipyによって配列の各サンプルへの操作は、単なる乗除算や関数の適用として記述できるので簡単に書けるのです。説明を加えますと、参照波の振幅には情報がありませんので、正規化するために振幅(複素数のabs)で割っておきます。さらに16ビットの数値を、最大1とするため1^15で割っています。そして、全サンプルの和を取ってサンプル数で割る操作、すなわち平均(average)を使っています。

image

このように反射係数を得る方法がわかったら、今度は周波数を変えながら、それぞれの周波数でこの処理を繰り返すことで、周波数特性が得られるはずです。USB(中身はシリアルと同じ)経由でコマンドを送って周波数を設定、バッファからサンプル値を取得し、反射係数を計算することを繰り返します。いくつか簡単な関数を作ってこの処理を実装します。linspaceで周波数の列を作って、これに対して反射係数の取得を繰り返すようにします。1MHzから300MHzまでをスキャンしてみます。繰り返しの部分はPythonのリスト包摂表記を使っています。

image

スキャンには6秒程度を要しています。無事、反射係数の配列が得られました。

いよいよプロットしてみます。横軸を周波数、縦軸として反射係数の振幅(絶対値abs)を取ると周波数特性となります。縦軸は対数としています。

image

おおむね横なグラフが得られています。理想的には周波数に依らず全反射で一定となるはずですが、実際には周波数が上がると振幅が下がってきます。これはミキサ等の周波数特性に依るものです。これは後で行う校正操作でキャンセルすることができます。

反射係数を複素平面上にプロットすると位相が回転する様子が見えます。

image

円弧を描いているのが判ります。原点中心の円を描くはずですが、高い周波数で振幅が減って行っているので原点へ近づいています。この回転や振幅の減少も校正でキャンセルされることになります。

さて、全反射が見えるようになったら、何か測定してみます。測定対象(DUT:Device Under Test)として100MHzのLPFを用意してみました。チップ部品を組み合わせて作ったものです。基板は秋月の16穴基板です。

image

回路とシミュレーションです。

image

NanoVNAで反射特性、ついでに通過特性を取るとこんな感じになります。通過特性を取得するのは、ポートを切り替えるコマンドを送るだけで、あとは反射係数の処理とまったく同じす。

image

緑色の通過特性がLPFになっていることがわかります。カットオフが100MHz付近になっています。通過と反射で振幅が違っていますが、これはTX側とRX側で特性が違っているためです。この違いは校正で消えますが、ダイナミックレンジを確保するためにPGAでゲインを調整しても良さそうです。

以上のように、LPFの反射と通過の周波数特性を得ることができました。まだ校正をしていない状態でのグラフですがそれっぽい特性が得られています。こんな感じで信号処理の方法を検討したのち、この処理の中身を実機のファームウェアへと移し替えていく予定です。このようにやると試行錯誤やデバッグが効率的に行うことができると思います。

今回300MHzまでスキャンさせていますが、実はこれには少々工夫があります。当初は上限112.5MHzと想定していたのですが、PLL上限900MHzの1/8の周波数です。Si5351Aを使って、3つの周波数を生成させていますが、うち二つはRF信号とLo信号で一定の周波数差で同時に周波数を可変する必要があります。もう一つの出力はTLV320AIC3204のクロックでこちらは8MHz固定です。前回説明したように112.5MHz以上の周波数を可変して使うには、PLL側を可変する必要があります。PLLは二つしか無いので、両方を可変に使ってしまうと、8MHz固定の信号を出せなくなってしまいます。そのため、112.5MHzが上限となると考えていました。さもなくば、別に水晶を用意する必要があると。しかし、よくよく考えると、両方のPLLを可変したとしても、合わせて同時にMultiSync側も調整して、8MHz一定の周波数を出力するようにしてやれば大丈夫ではないかと。実際試したらOKでした。整数比でない分周をつかうことになるため信号純度の点で少々不利になりますが、許容範囲内でしょう。この方法でPLLの個数に由来する周波数上限の制約が無くなり、しかも仕様外ながらSi5351Aの上限が300MHzを越えることが判ったので、思いがけず予定以上の広い測定範囲が得られることになりました。

次回は校正の予定です。

リファレンス

comments powered by Disqus