SDR

FM BPFのシミュレーション(2)

前回に引き続き、トラ技の記事の回路をシミュレーションしてみます。 今回はLNAの電源に使用されているフィルタ部について行いました。

記事で使用しているPSA4-5043は入手できなくなっている(?)ようなので、PSA4-5043+を使用するつもりです。 このチップは、RF出力と同じピンから、チップの電源を供給します。デジタルだと考えられないですが、 結局電圧のバイアスをかけるだけであり、RF信号はいずれにせよ後段でAC結合でバイアスは取り除きますので、 問題にならないのだと思います。

でも、この端子から電源を入れるとなると、こちらにノイズが混入しては元も子もありません。 電源部のためのフィルタ回路が組まれています。

シミュレーション結果は次のようになりました。

まずは、DCから120MHz全体のゲインの様子です。

“LNA Power input filter DC-120MHz”

次に、DCから11MHzまでを拡大してみます。

“LNA Power input filter DC-11MHz”

1MHzを越えると-50dB以上減衰できているようです。低周波数の領域についてはそれほど減衰していません。 こちらについてはLDOで落とすことも考えられますが、果たして必要なのか? この領域であれば、 アナログにノイズが混入しても、デジタルミキサで周波数を移動してLPFをした時点で取り除けるような気もします。

**2017/9/9追記:**次は、入力側のキャパシタの値を0.1uFから10uFまで変化させたときのシミュレーションです。 容量が大きくなるほど減衰量が大きくなっていることが分かります。 製作した基板に使用した0603サイズでも10uF程度のセラコンは入手できそうでした。

“LNA Power input filter DC-11MHz parametric”

下記も参考になりそうなので、後々読んでみたいと思います:

SW電源ACアダプタのノイズ対策①

SW電源ACアダプタのノイズ対策②

FM BPFのシミュレーション(1)

以前製作したADC基板をもう少し良くするために、ADC基板とRFフロントエンド基板を分離して製作することを検討しています。

現在RFフロントエンド基板の回路図を検討しています。実はそのものずばりのものが、トランジスタ技術2015年4月号 170ページからの記事"フルデジタルFMラジオ用アンチエイリアスBPFの製作"という記事にありました。

記事では、簡易なBPF(76-95MHz)を通した後にLNAでゲインアップし、その後、 記事の主な内容となっているBPFを通すというものになっています。

今回は、LNAの前の簡易BPFをシミュレーションしてみました。簡単のため、LやCのESR(寄生抵抗)は無視しています。

“2 pole BPF”

上のような結果になりました。緑の実線が左軸のゲインです。記事の通り76-95MHzは、ほぼ平坦な特性です。

ADC基板の電源測定

オシロスコープを入手したので、早速電源のノイズをみてみました。

ノイズ測定をするにあたって、正確な測定のためには、GNDクリップは使用しないで、 直近のGNDで測定しないと意味がないようですが、ノイズの大きさの傾向だけはつかめるかと思いました。

Z-turn boardから送られてくる3.3V電源。これはスイッチング電源の出力です。

"+3.3V"

上記電源がFBを通過した後の様子

"+3.3V"

相当ノイズは減っているように見受けられます。

次に、LDO出力の3.0V(上の二枚と異なり、垂直軸が10mVレンジなのに注意)

"+3.0V"

上記がFBを通過した後の様子

"+3.0V"

スイッチング電源ではないのでFBはいらなかったかもしれません。

いずれにしても、LDO出力のノイズが大きすぎるような気がします。 全くノイズが減少しているように見受けられません。

急ぎで製作してしまったので、LDOの推奨レイアウトのようにベタにしなかったのがまずかったのか、 それともそのほかの理由があるのか検討しないといけませんね。

2017/7/28 追記: 今になって分かったのですが、LDOは一般的に数百kHz以上のノイズについてはほとんどフィルタの役割を果たしません。そういった周波数帯のノイズを除去したいのであれば、ちゃんとしたフィルタを通す必要があります。 上記の結果はそれを確認していることになります。

また、LDOでできるだけノイズを除去したいのであれば、ドロップアウト電圧も1V以上とることが推奨されるようです。 あまりにドロップアウト電圧が小さいと、ノイズ除去能力も低減します。

上記のような内容は、LDOのデータシートをよーく読めばわかります。また、LDOに使用されているオペアンプの特性からしても、 高周波のノイズ除去はできないのは明らかそうです。

SiglentのDSOを購入

FMステレオ復調のところは、時間が無くて取り組めていません。

その間に、基板の性能の方を調べて見たくなり、いろいろとオシロスコープを物色しました。

最初はTektronixの中古をヤフオクなどで落とそうかと思ったのですが、最終的には新品を購入してしまいました。

大体100MHzの帯域が測定できる必要があります。それと、FFTも欲しいです。 安くて確実そうなのはRIGOLのDS1054Zかと思いましたが、 最終候補になったのは、HantekのDSO5102Bと、 SiglentのSDS1202X-Eでした。 前者は大体339USD, 後者は379USD程度です。

SDS1202X-Eは、I2C, SPI, UART, CANなどの信号のデコード機能も持っているのが優位点でした。 また、SDS1202X-Eの方が新しいです。こちらによると、Zynqの7020を使用しているようです。

結局、SDS1202X-Eを購入しました。最初はAmazon.comから買おうかと思いましたが、 調べてみたらAliExpressにて送料無料で購入できることがわかり、 そちらに出店していたSains Electronix Storeから購入しました。 6/15(木)の夜に注文して、6/19(月)には到着しました。早いです。

(2019/1/12現在、日本のAmazonからも購入できるみたいです)

注文したら、すぐにお店から、“USコードを選択していたけど、EUコードしか在庫がないんだよ。 USコードは2週間待ちなんだけど、EUコードで送っても良いかい? (意訳)“という内容のメッセージが届きました。 “いやいや、待っても良いからUSコードでお願い。でもできるだけ早くね! (意訳)“と返しました。 そうしたら翌日6/16(金)には発送のお知らせが来たので、まさかEUコードが添付されているのではないか、 とはらはらしましたが、到着した商品を確認したら、ちゃんとUSコードが添付されていました。

うっかりしていたのは、このコードは3ピンタイプだったので、家にある電源プラグに接続するために変換プラグを購入する必要がありました。こういうやつですね。 あるいは3ピン2ピンケーブルでも良いですね。

AliExpressは初めて使いましたが、楽天のように店舗によって対応がまちまちのようです。 今回使用した店舗は迅速で満足でした。Web上での評価も高いようです。梱包も問題ありませんでした。

“同梱物”

当たり前ですが、プローブが2本ついています。写っていませんが、USBケーブルも添付されていました。

“SDS1202X-E”

オシロ本体です。とりあず、電源を入れてプローブ補正だけしました。

早速ADC基板を少し測定してみました。 基板に電源は投入せずに、FMアンテナを接続して、BPFの後の個所にプローブを当て、FFTをしてみた結果が次になります。 ちなみに、GNDは基板上に立てたピンでとっているので、あまり良くないかもしれません。

“BPF後のFFT”

そういえば、画面キャプチャも本体でできるはずですね。わざわざ撮影する必要は無かったですね。

それは置いておいて、上の画面では84.7MHz近辺を拡大しています。Y軸の単位はdBVrmsになっています。 大体20dB位は信号が出ているようですね。

問題は、電源を投入した時の様子です。順次調べていこうと思います。

FMステレオパイロット信号の確認

前回までに、FM復調処理全体のFPGA実装とDACによるヘッドフォン出力が完成しました。

今回は、ソフトウェアを少し修正して、FM復調した信号そのものをFFTして観察できるようにしました。

これはステレオ復調のための布石です。

“FM復調信号のFFT画面”

FFT画面下部のMHzという表示は嘘で、KHzです。500kHzのサンプリング周波数でFM復調処理が動作していますが、 FFTを見てみると、確かに19kHzのところに信号が常に一定値で含まれています。 これがFMのパイロット信号だと思われます。この信号を2倍した38kHzを中心として、 L-Rの音声信号がAM変調されDSBとなっているそうです。

ステレオ復調にあたっては、この19kHzにロックした正弦波をFPGA内部で生成する必要があります。

FM復調のFPGA実装(4)

前回までに、FM復調処理全体のFPGA実装が完了しました。

今回は、製作した基板上に実装されているオーディオDAC NAU8822 を動作させ、リアルタイムにヘッドフォン端子から音声出力が得られるところまで確認しました。

これで、ひとまずFMラジオの完成です。以下がFM信号をFFTした画面です。

“FM信号のFFT画面”

やっとリアルタイムで音が聞けるようになったので、アンテナの向きを変えたり、基板上の部品を触ってみたりして、 ノイズがどう変化するかを確認できました。

FPGA基板に載っている大きいインダクタを触るとかなりノイズが乗る。また、 デバッグのために接続しているUSBケーブル、LANケーブルを抜くとノイズが減る。 余計なケーブル類を除いてアンテナの向きを最適化すると、自分の耳ではノイズが聞こえないくらいのレベルでは 音声が聞けるようになりました。

基板が到着してから暇を見つけて少しずつ進めてきました。 結局、ここまで来るのに、1カ月ちょっとかかりました。 ADC動作のために修正が必要な基板のミスは無くて、半田コテを一切使用せずここまで来ることができました。 また、デバッグにあたりショートチェックと電圧測定のためにマルチメータは使いましたが、 DSOは使用しないで済みました。

最後に少し苦戦したのは、DACのレジスタ設定でした。なかなか音が鳴らなくて、 いよいよオシロが必要かと思いましたが、たった1bitを変えるだけで音が出るようになりました。 やれやれ。

ここまでできたので、ひとまず満足です。まだソフトウェアの作りこみは甘いので、 FPGAで動作するファームウェアやPCのソフトウェアの使い勝手をもう少し向上させたいと思います。 また、現状JTAGケーブル、LANケーブルも接続してNFSマウントでデバッグしています。 これを一旦は単独動作するようにまとめたいとも思っています。

ラジオ機能としては、あとはステレオ再生の実装でしょうか。

参考にしたページ:

現状上記の状態ですが、本基板を試してみたい、というご要望がありましたらtwitterでお知らせください。 件名に"[ADC基板]“と入れていただけると助かります。 利用するには、最低限Z-turn boardとACアダプタ、SMAメスに接続できるFMアンテナが必要です。

また、「自分の持っているXXX FPGA基板でも動作させてみたい」というような要望につきましても、 ひょっとしたら対応可能かもしれません(基板書き換えで)ので、お知らせください。

以下は備忘録

アンテナを装着しないでFM側入力をキャプチャしてFFTしたもの。

“アンテナ未装着時のFFT”

同様に、アンテナを装着しないで(かつアンプも通さず)AM側入力をキャプチャしてFFTしたもの(こちらはシングルエンド入力でADCを使用)。

“アンテナ未装着時のFFT”

次に、アンテナを装着しないで、アンプを通したAM側入力をキャプチャしてFFTしたもの。

“アンテナ未装着時のFFT”

FM復調のFPGA実装(3)

前回までに、FM変調のキモであるarctanのところまでFPGA実装しました。

今回は、それに続く偏角の差分計算から、FIR3段とデエンファシスまでFPGA実装しました。

FM復調全体の流れは次の図のようになっています。

“FM flow”

前回までは、最初のFIRフィルタから160MHzで駆動するようにしていましたが、 FPGAのVivadoプロジェクトを2017.1にアップグレードしたら、CORDICが160MHzで動作しなくなってしまいました。 そのため、FM復調全体までは40MHzで行うようにしました。

おかげで、FIRに使用するDSPの数が増えてしまいました。リソース使用量の観点からすると、 できるだけ高速で動作させたほうが(リソース使用量が減って)望ましいのです。

前回までにFIRフィルタの使い方は分かったので、ひたすら必要な逓倍数のフィルタを作成し、 連結します。ただ、FIRフィルタの間は小さなFIFOを入れて、データ出力間隔が均等にならないのを埋め合わせています。

また、FM復調のための偏角の差分計算は、C#ではこちらの記事で書きましたが、 Verilogで書くにあたっては、

parameter signed[33:0] PI = (2.0 ** 29.0) * 3.1415926535897932384626433832795;
parameter signed[33:0] PI2 = (2.0 ** 30.0) * 3.1415926535897932384626433832795;

のようにπと2πを定義して、

assign  w_atan_tdata2   <=  {w_atan_tdata[31], w_atan_tdata[31], w_atan_tdata};
assign  r_atan_tdata2   <=  {r_atan_tdata[31], r_atan_tdata[31], r_atan_tdata};

always @(posedge w_fir_ck) begin
    if (w_atan_tvalid) begin
        r_atan_tdata    <=  w_atan_tdata;
        if (w_atan_tdata2 - r_atan_tdata2 > PI)
            r_atan_diff <=  w_atan_tdata2 - r_atan_tdata2 - PI2;
        else if (w_atan_tdata2 - r_atan_tdata2 < -PI)
            r_atan_diff <=  w_atan_tdata2 - r_atan_tdata2 + PI2;
        else
            r_atan_diff <=  w_atan_tdata2 - r_atan_tdata2;
    end
end

としています。w_atan_tdataは小数部29bitの符号付き32bit固定小数点数なので、 34bitに符号拡張してから、πを2^29乗したものと比較します。r_atan_diffは32bitに戻ります。 これが偏角の差分値になります。

最後のデエンファシスも小数点位置に気を付けてIIRフィルタを実装しました。 安直に実装したデエンファシスの回路は160MHzではタイミングエラーを起こしたため、 非同期FIFOで40MHzに落として運転しました。そう思うと純正IPのFIRが160MHzでも動作しているのは、 さすがによくできています。

FM復調のFPGA実装(2)

前回までに、ミキサとCICはFPGA化ができました。

今回は、それに続くFIR一段分とCORDICによるarctanを実装しました。

FM復調全体の流れは次の図のようになっていますが、今回は図中のarctanまでFPGA化しました。

“FM flow”

NCO, ミキサ, CICは自分で実装しましたが、 FIR, arctanはそれぞれXilinxのFIR, CORDIC IPを使用して楽をしました。 FIRフィルタはマルチチャンネルに対応できるので、回路的には1つだけでI,Q両方を扱うことができますが、 乗算器も潤沢にあるので、それぞれのチャンネルでFIR回路を置いています。 また、arctanもY,X入力最大幅の49bitまで使用しています。

図の最下部にある40MHz, 160MHzというのはそれぞれの回路ブロックの動作クロック周波数になります。 160MHzはADCに使用されている40MHzのクロックをMMCMにて4逓倍して生成します。

1段目FIRの入力は、わずか1.25MHzしかありませんので、160MHzに対して160/1.25=128となり、 128クロックに1回しかデータが入力されません。さらに出力は2/5に間引かれますので、 平均して320(=128*5/2)クロックに1回しか出力されません。

このように、データは回路の動作周波数に対して間欠的にしかやってきませんので、 255タップのFIRフィルタを実装するにしても、ほんの少しの乗算器を使用するだけで実装できます。

ただ、最初はFIR, arctanを200MHzで動かそうとしましたが、 arctanのところでタイミングがメットしませんでした(WNS < 0)。 これだけのビット幅があるのに160MHzで動くのだから大したもんです。

arctanの出力をPCに取り込んで、残りの部分をソフトウェアで処理したところ、ちゃんと音声が再生できました。 あとは、残りの回路を粛々と実装します。FIR IPの使い方は分かったので、 手で実装しないといけないのはdiff(偏角の差分)とde-emphasisの部分になりそうです。

以下はおまけと備忘録

XilinxのFIR IPは、coeファイルというテキストファイルを指定することで、FIRの係数を設定できますが、 このファイルでは"-6.595122999934834e-03"といった指数表記の小数は使えないようです。 “-0.0065951…“のようにする必要があります。そのため

cat data.txt | awk '{print sprintf("%.12f", $1)}' > coef255_008.coe

のようにして表記を変更しました。

使用しているFIR, CORDIC IPコアの設定画面は次のようになっています。

FIR Compiler

“FIR Filter Options”

“Channel Specification”

“Implementation”

“Detailed Implementation”

“Interface”

“Summary”

CORDIC

“Configuration Options”

FM復調のFPGA実装(1)

前回までに、ADCでキャプチャした生データをパソコン上で処理することで、 FMラジオを視聴できることが確認できました。

PC上のソフトウェアでFM復調を行っている部分を、徐々にFPGA化していこうとしています。

いきなり全体をRTLで実装しても、動作しなかった場合のデバッグが大変です。 それで、ADCに近い側からFPGAの回路に落とし込みます。今回は複素ミキサ(ADC入力にチューニング周波数のsin, cosを掛け算することで、I, Q信号を得る)と、 CICフィルタを実装しました。

2の補数表現とビットシフトを注意深く行えばそれほど難しくないはずの回路でしたが、わりと手こずりました。 複素ミキサはFPGAのBRAMにてテーブルルックアップを行ってsin, cosの値を得るようにしています。

具体的には、32bitの値を持つ400エントリを使用して、各エントリに対応するsin, cosの値を符号付きで13bitずつ入れています。 なぜ400エントリかというと、40MHzのサンプリングレートで例えば84.7MHzを受信しようとする場合、 これはナイキスト周波数以上なので実際には4.7MHzとしてADCから見えます。 (4.710^6) / (4010^6) = 47 / 400ですから、ADCの400サンプルに対して、4.7MHzは47周期現れます。 この400回分について、sin(2 * π * i * (47/400)) (i=0…399)をテーブルとして準備しておきます。 テーブルの中身自体は、Zynqで動作するLinuxアプリケーションにて初期化しています。 BRAMはZynqのアドレス空間と、RTLの両方からアクセスできるようにTrue Dual Portで動作させています。

ADCの各クロックごとにアドレスをインクリメントすることで、対応する周波数のsin, cosの値を得ることができます。 それをADCから出力されている符号付き12bitと掛け算し、下位ビットは切り捨ててCICフィルタに入力します。

CICフィルタは3ステージの1/32間引き(1.25MHz出力)を行っています。出力は29bitとしています。

これで毎秒のデータ量は1.25MHz*8bytes=10MBytesに減少しましたので、メモリ上に取り込むことのできる時間が一気に長くなりました。 PC側でサンプリングレートの調整を実装すれば(基板に実装されている発信器の周波数とPC上の周波数は異なるため、 48kHz出力を行うにしても、クロックレートの微調整のためにサンプルレート変換が必要)、 リアルタイム転送とFM変調処理が行えるのですが、そちらはまだ今後の課題ということで。

結局最後まで手こずった原因は、BRAMのアドレスの下位2bitは無視されていることに気づかず、 0-399までのカウンタをそのままアドレスに入力していたことでした。 0-399のカウンタに下位2bit"00"を付加してBRAMの32bitアドレスとすることで、 想定通りの正弦波が得られたようです。

それでも、PC上で処理した場合より明らかに音質は悪いです。もう少しミキサのビット数を増やしたりしてみようかと思います。

2017/4/20追記: ミキサの出力を17bitにして、CICを32bitまで拡張しました。 ミキサ出力の部分も実際のデータを観測して、オーバーフローしない範囲でできるだけ下位ビットを取るようにして、 可能な限り精度を落とさないようにしました。CICの結果から残りをパソコンのソフトで処理してみたら、 かなり音質は改善しました。これならひとまず良さそうです。 残るFIRとCORDICによるarctanの実装を粛々と行っていけばFM復調のFPGA化が完成する予定です。

また、これまでソフトウェアではarctanを求める前に複素数の割り算をすることで、偏角の差分を一発で求めていました。 でも、FPGA化する場合、これだと乗算と加算が入るので、CICのデータが32bitあると64bitほどになってしまいます。 それで、まずarctanを各データに対して行って、その結果の偏角を引き算する、という計算順序に変更しました。 arctanが返す角度の範囲が-πからπまでなので、単純に引き算するだけだと、この範囲を超えてしまうことがあります。 そのため、下記のように必要な場合2πずらすようにしました。

    private double[] fm_demodulate_sub(double[] i, double[] q)
    {
        double[] result = new double[i.Length];
        double prev = 0.0, tmp;

        for (int x = 0; x < i.Length; x++)
        {
            tmp = Math.Atan2(i[x], q[x]);
            if (tmp - prev > Math.PI)
            {
                result[x] = tmp - prev - Math.PI * 2.0;
            }
            else if (tmp - prev < -Math.PI)
            {
                result[x] = tmp - prev + Math.PI * 2.0;
            }
            else
            {
                result[x] = tmp - prev;
            }
            prev = tmp;
        }
        return result;
    }

これならばarctanの計算に必要な精度はI, Qそれぞれ32bitで良いことになります。

FM復調(モノラル)の実装

前回までに、ADCでキャプチャした生データをパソコン上で処理することで、 AMラジオが視聴できることが確認できました。

加えて今回はFMも復調できるようになりました。

FM復調の流れは、次のようになります。

  • ADCデータ(12bit@40MHz)に、チューニングしたい周波数のsin,cosを生成(NCO)してそれぞれ掛け算してI, Qデータを得る
  • I, Qデータを4ステージCICフィルタで1/32に落とす(1.25MHz)
  • 続いてFIRフィルタで2/5倍(500kHz)に周波数変換する。2/5倍で使用する係数は255タップ、遮断周波数0.08fs(fc=200kHz)とする。
  • 500kHzサンプリングのI, Qデータの隣り合ったサンプル同士からarctan(タンジェントの逆関数)をもとめる。 具体的には、Math.Atan2(i[x-1]*q[x] - q[x-1]*i[x], i[x-1]*i[x] + q[x-1]*q[x])を求める。 I, Qを複素平面のx,y座標とみなして、C[x]とするとき、arctan(C[x+1]/C[x])を求めることで、サンプル間の偏角の変化量を求めることになります。
  • 上記の偏角の変化量をFIRフィルタで2/5倍(200kHz), 3/5倍(120kHz), 2/5倍(48kHz)に周波数変換する。 係数はすべて255タップ、遮断周波数はそれぞれ0.08fs(fc=80kHz), 0.08fs(fc=48kHz), 0.0625fs(fc=15kHz)とする。0.0625fsとすることで、15kHz以下を通過させるLPFとなります。 19kHzにステレオ放送用のパイロット信号が入っているので、その前の段階で十分に減衰できるようにします。
  • 48kHzまでサンプルレートが落とされたデータ系列に対して、デエンファシスをかける。具体的には、 Low-Pass Single-Pole IIRフィルタを通します。 上記ページによれば、減衰量dはd=e^(-2pifc)という関係になるようです。fs=48kHzなので、大体3kHzで-3dBになればよいようなので、 fc=3kHzとし、d=e^(-2pi(3/48))=0.67523…となります。
  • デエンファシス後のデータを(適当にゲイン調整を行ってから)WAVファイルに出力する。

上記のように、FMでのステレオ復調は行っていません。これでなんとか音声として聞こえるようになりました。 各フィルタの遮断周波数は、変換後の1/2fsよりもそれなりに小さいところで設定しておかないと、折り返しがもろに入ってしまうと思われます。 そのため、上記のように1/2fsの80%, 62.5%と設定しています。

ここまでで、曲がりなりにも論理的にはAM/FMの復調ができることは確認できました。すぐに思いつく今後の方向性としては

  • FPGA化
  • ADCの精度確認と改善

があります。後者は機材をそろえたり、受動部品の定数を変更したりしてみないと難しいと思われるので、 ひとまずFPGA化の方を少しずつ進めていこうと思います。また、基板上には音声出力用のICも搭載しているので、 そちらの動作確認もしないといけません。

参考にしたページ

FMトランスミッタ: プリエンファシス(1)

三重大学の資料?

エンファシス

石川高専 山田洋士 研究室 (FIRフィルタの窓関数法による設計)