SDR

ADC基板でのAM/FMキャプチャと復調

ADC基板でAM信号をキャプチャして、 パソコン上のソフトウェアでAM復調を行う、というところまで最低限動作しました。

波形を取得しFFTしたときの画面を示します。

“AM Capture”

赤丸で囲ってあるところは、それぞれ810kHz(AFN), 1422kHz(RFラジオ日本)と思われます。 実際にC#で適当にこしらえたソフトウェアで810kHzをAM復調してみたら、カントリーミュージックが流れていました。

AM復調の流れは、ざっと次のようになります。

  • ADCデータ(40MHz@12bit)に、チューニングしたい周波数のsin,cosを生成(NCO)してそれぞれ掛け算してI, Qデータを得る
  • I, Qデータを4ステージCICフィルタで1/32に落とす(1.25MHz)
  • 続いてFIRフィルタで2/5倍(500kHz)、2/5倍(200kHz)、6/25倍(48kHz)と変換を行う。2/5倍で使用する係数は51タップ、遮断周波数0.2fs。 6/25倍で使用する係数は51タップ、遮断周波数0.04fs。
  • 48kHzまで落としたI, Qデータからsqrt(I^2+Q^2)を求めて振幅を求める(AM復調)。 この値をwav形式(モノラル)でファイルに出力する。

SDRについては勉強中の身なので、上記のタップ数や遮断周波数の設定などはあまりよろしくないのかも? しれません。 現状NCOとFIR演算は整数演算ではなく、浮動小数点演算を用いています。 また、FIRのために実装したポリフェーズフィルタもコードが正しいか、まだちょっと不安です。

ただ、上記画面からもわかるように、他にも954kHz(TBSラジオ, 100kW)や1134kHz(文化放送, 100kW), 693kHz(NHK第二, 500kW)などの、出力が大きい局の信号がほとんどとれていません。

Wikipedia - AFNによれば、AFNは出力が50kWらしいので、 他の局も十分受信できても良いように思います。 手元にちゃんとしたAMアンテナが無いので、FMロッドアンテナを基板に装着しているのですが、それが原因なのか? それとも、サンプリングの折り返しなどの原因があるのか(AM側の入力はBPFなどを一切設けていない)? まだ不明です。

また、810kHzなども、「なんとか聞こえる」という程度であり、お世辞にも音質は良いとは言えません。 所有している乾電池式ポータブルラジオの方がはるかに音質が良いです。 もっとも、これについては復調処理に問題があるのかもしれません。

4/5追記: やはり間違いがありました。Wikipedia - サンプリング周波数変換 の通り、a/b倍の周波数変換をするときには、変換後の周波数の1/2の周波数を遮断周波数としなければいけないようです。 上記の設定だと、変換後の1/2fs以上の周波数が折り返してしまいます。 そういうわけで、2/5倍に使用する係数は0.1fsを遮断周波数とし、6/25倍に使用する係数は0.02fsとしました。 また、タップ数もそれぞれ71, 255に増やしました。 そうしたら音質が(まだまだ十分ではないですが)かなり改善されました。

4/11追記: さらに変更して、現在の信号処理の流れは次のようになりました。

  • ADCデータ(40MHz@12bit)に、チューニングしたい周波数のsin,cosを生成(NCO)してそれぞれ掛け算してI, Qデータを得る
  • I, Qデータを4ステージCICフィルタで1/32に落とす(1.25MHz)
  • 続いてFIRフィルタで2/5倍(500kHz, fc=156.25kHz)、2/5倍(200kHz, fc=62.5kHz)、3/5倍(120kHz, fc=48kHz)、2/5倍(48kHz, fc=15kHz)と変換を行う。 使用する係数は255タップ。2/5倍で使用する係数の遮断周波数は0.0625fs。3/5倍で使用する係数の遮断周波数は0.08fs。 上記の通り、2/5倍で0.1fsとすることもできるとは思いますが、それだと1/2fsで-3dBしか落ちませんので、 周波数変換後の高音部にかなりエイリアスが入り込んでしまうと思います。
  • 48kHzまで落としたI, Qデータからsqrt(I^2+Q^2)を求めて振幅を求める(AM復調)。振幅が符号付き16bitに収まるようにゲイン調整を行う。 この値をwav形式(モノラル)でファイルに出力する。

追記終わり

ちなみに、FM側の入力波形を見てみると、次のようになっています。

“FM Capture”

ADC基板到着

ついに、Elecrowに発注していたADC基板が到着しました。

3 / 9 (木)にPayPalにて支払いを行い、3 / 29に発送のお知らせメールが到着し、3 / 30 (木)に到着しました。 Elecrowから送られてきたL/Tは2-3weeksでしたが、ぴったり3週間で到着です。

3 / 29までは全く音沙汰がなかったので、ちゃんと進んでいるのか、それとも実装に失敗しているなどの問題が起きていないか、心配でした。

完成した写真を送ってくれたという方もいるようですが、私の場合はいきなり発送されました。 OCSの履歴を見てみると、3/28の夜に中国から送られて3/29の午前には日本に到着していました。 配達はさすがに速いですね。

ちなみに、基板2枚実装で241USD, π割引3.14USDで237.86USDでした。日本円で27,784円でした。1USD=116.8円なので、 あまりレートは良くないタイミングでした。

基板の包装は次のような感じでした。

基板のパッケージ

テンション上がります。

ちなみに、かの有名なElecrowガチャは2枚でした(実装したのも2枚)。

おまけ基板

ステンシルは入っていませんでした。再度製造を依頼する場合に必要になるので、こちらから頼まなければ保管しておいてくれているのかもしれません(未確認)。

ADCの部分は次のような感じです。

ADCパターン

KiCadに習熟していないせいで、若干センターのGNDが甘い気もしましたが、勢いで作ってしまいました。

あらかじめ購入しておいたSMA-BNC変換コネクタとジャンパを装着した状態が次です。

テンションMAX

うーん、美しい。初めての基板製作で我ながらよくここまで頑張った。 フットプリントがおかしくて墓石になることもなかったようです。 また、ちゃんとDIP部品もしっかり基板に入っています。ヘッドフォン端子はフットプリントが結構変態的だったので、ちゃんと基板に入るか心配でした。 ちなみに、画面下の赤いのは、SMAコネクタを保護しているプラスチックのキャップです。

ちょっと部品間隔が狭すぎるかと予想していましたが、しっかり実装できているようです。抵抗アレイはほとんど横並びです。 自分の実力だと、これほど近接していたらチップ部品の交換はしんどいですね。

右下のジャンパの接続のためのシルクも小さいけどしっかりと見えます。

それにしても、実際の基板ができた時の満足感はすごいですね。もうデバッグはいらない気分になってしまいます。

この基板をこれまた購入済みのZ-turn Boardに装着すると、次のような感じです。

最高の組み合わせ

さすがに80ピンもあると抜き差しは慎重にやらないと危険です。

1枚の基板はこの80ピンコネクタが少し曲がっているという不具合がありましたが、ひとまず手でなんとか挿入できるくらいまでは真っ直ぐに直しました(汗)。

あ、もちろん、電源を入れる前に電源とGNDがショートしていないことは確認しましたよ。

いよいよ(すぐにアダプタを抜ける態勢で)緊張の電源ON!!

「ピー」 ….. え??? ひとまず電源を抜きます。

おかしい?? ショートしている?? というわけで基板チェック開始。いろいろ調べてみたけど、やはりショートは問題ない。 どうやらJ6のジャンパを入れてADCの電源が入ると音が鳴る。J6がoffだと音はしない。

いろいろ調べてみたところ、どうやらビープを駆動するNPNトランジスタのゲートに接続されているネットがオープン状態なのですが、 そこの電位が数百ミリボルトあがっているようでした。それでトランジスタがONしてしまっているのではないかと思いました (参考)。 こうなってしまっている原因は不明ですが、ショートは恐らくないことを考えると、 ADC出力が開始されることで、当該ネットに近い他のネットからのクロストークを受けてしまっているのかもしれません。

というわけで、本来ならばビープのネットをプルダウンするのが良い解決策だと思いますが、FPGAで当該ネットをLow駆動することで音は出なくなりました。 ひとまず変更したデザインをQSPI ROMに書き込んで、起動時にコンフィグが終了すれば音が止むようになりました。

ちょっと先が思いやられますが、デバッグを続けます。

ADC基板のBPFのシミュレーション

今回は、LTspiceを使用して、 ADC基板に実装しているBPF(Band Pass Filter)の周波数特性をシミュレーションしてみました。

“Simulation”

実線が左側の軸(振幅)に対応し、点線が右側の軸(位相)に対応しています。

初めて使ったので、少し使い方に迷いましたが、比較的簡単に使えました。 シミュレーションを行う周波数を50M-120Mと入力したらメガヘルツになるかと思ったら、 Mはミリと解釈されるようです。メガを指定するにはmegと入力しないといけません。 LTSpice入門を読んで分かりました。

シミュレーション結果を見てみると、-3dBになるのは大体60MHzと105MHzあたりでしょうか。 70-90MHzの範囲はほぼ0dBで通過しているのが見て取れます。 もう少し急峻にバンド外を落とすかと思っていましたが、わりとゆるやかな特性なのですね。

Wikipedia によると、これはバターワースフィルタのCauer形のようです。ロールオフ特性は緩やか、とはっきり書いてありました。

DDSデータキャプチャとFFT表示

前回、ADCキャプチャのためのFPGAとLinux周りの準備を行いました。

まだ実際のADC基板は完成してきていないので、FPGAにてDDS(Direct Digital Synthesizer: デジタル的に正弦波を生成する仕組み)を使用して、仮想的なデータを作ってみました。

具体的には、FPGAにDDS Compilerをインスタンシエートして、 PCのソフトウェアにてキャプチャ&FFTを実行しました。

DDS Compilerにて作成するIPは、3MHzの正弦波としました。

DDS compiler

12bit出力ですが、AXI Streamポートは16bit幅となっています。どうやら16bitの内、下位12bitにデータが入っている様子でした。符号付きデータです。

この12bitを5データ集めて、かつ4bitのダミービットを付加して64bitとし、前回のAXI DMA IPにてDDRに転送します。 PC側のソフトウェアは、手っ取り早くC#で作成しました。

いろいろ細かいデバッグを行って、現状次のような表示になっています。

ADC_FFT

画面上部にキャプチャした波形そのものを少し表示しています。横軸はサンプル番号です。 マイナスからプラスの範囲でしっかりフルスケールの正弦波となっている様子がわかります。 画面下部はキャプチャしたデータをFFTしてdB表示しています。 どうも使用しているFFTライブラリの正規化の挙動が不明で、0dBを超えてしまっています… 3MHzにびしっと信号があることを確認できます。

FFTライブラリには、C#でマイク音声をFFTするを参考に、 Math.NET NumericsをNugetにてインストールして使用しました。

これで基板が来るまでの準備は大体満足するところまで作成できました。

ADCデータキャプチャのためのLinuxとFPGAの設計

現在Elecrowにて製作中のADC基板ができてきた折に、Z-turnボードと接続してイーサネットにてADCデータを取得するためのファームウェア周りを作成しています。

FPGAについて

Zynqに接続されているDDRメモリにADCデータを保存します。 DMAマスタをRTLで記述するのは割と面倒(とにかくAXIはポートが多いので、どうしても行数は増える)なので、できるだけ楽をしたいと思います。 そういうわけで、Vivado HLS一択です。DMAコントローラのコードは次のように至極単純です。

ちなみに、AXI DMAを使えばいいじゃないか、という意見もありそうです。 しかしながら、AXI DMAは一回の転送で最大8MBしか転送できないという理解不能な制限があるので、今回はわざわざ作成しました。 SGDMAを駆使すればできると思いますが、とりあえずデータを取り込むことが目的なので、そのあたりは別途余裕ができたところで検討したいと思います。

#include "hls_stream.h"
#include "ap_int.h"
#include "axi_dma.h"

void axi_dma(ap_uint<64>* addr, ap_uint<32> offset, ap_uint<32> len, hls::stream<ap_uint<64> > &in){
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=offset
#pragma HLS INTERFACE s_axilite port=len
#pragma HLS INTERFACE m_axi depth=4096 port=addr
#pragma HLS INTERFACE axis port=in
    ap_uint<32> i;
    
    for (i = 0; i < len; i++){
#pragma HLS PIPELINE
    	addr[offset+i] = in.read();
    }
}

ん?Hugoでc++のシンタックスハイライトが効かない…

AXI Liteインタフェースでoffsetアドレス、転送長をレジスタで設定します。また、モジュールの開始終了もAXI Lite経由で操作できるようになっています。

RFの電界強度からADC電圧を計算してみる

ようやく設計した基板を製作しようかというところですが、そもそもラジオを受信してADCでデジタルデータに変換した際に、 一体どれくらいの電圧になるのか、ということを知りたかったので、少し調査してみました。

中波受信用ループアンテナ その6 (AMラジオ放送の受信電界強度を予測) に計算例があり、記載されている条件では39.5[mV/m]という値が予測されています。

次に、この値をdB表記と突き合わせて検算してみます。 こちらのページで39.5[mV/m]を入力して計算してみると、 39.5[mV/m]は-15.0578dBmに相当しそうです。

ところで、dBmによると、0dBmは50Ωの終端で1mWの電力に相当します。 これは電圧でいうと、0.224Vになります。電力なので、10dB増加すると10倍の電力になります。3dBでおおむね2倍の電力です。

戻って、-15dBmは-16=-10-3-3よりは大きいので、1022=40で1/40の電力(以上)に相当します。電力が1/40なので、 抵抗値が固定ですからP=I^2 Rからして、I^2が1/40になります。したがって、電流値が1/sqrt(40)=0.158倍。 V=IRで線形なので、電圧についても0.158倍。よって、0dBm=0.224[V]から-15Bm=0.224*0.158=0.0354[V]=35.4[mV]と求められます。 元々の値が39.5[mV/m]という値でしたので、dBとの変換はこの考え方で正しそうです。

2Vp-pで12bit分解能のADCを使用すると、1LSBは2 / 4096=0.488[mV]になります。

上記の計算が間違っていなければ、39.5 / 0.488=81LSB程度の波形が観測できることになります。 この程度の値が出てくるのであれば、ADCの実効分解能が10bit程度(=1/4)でも20LSBになります。

同様に、TBSラジオのカバレッジエリアでは、 当地は2mV/m圏内なので、2Vp-pでの4.1LSB。 これからすると、2mV/m程度の強度になると、12bit分解能でギリギリのように思われます。

ADC基板ほぼレイアウト完成

前回から回路図をさらに追加し、オーディオ出力部分も回路を引きました。 それからBOMを作成し、部品のフットプリントを作成、レイアウト、と進んで、 ようやく基板のデータがほぼ完成しました。一連の作業はKiCadにて行っています。

とにかく大変でした。まずはKiCadで基板レイアウトをするための操作に慣れるのも。 こればかりはDon’t think, feel.という感じです。とにかく手を動かしているとわかってきました。

4層基板でレイアウトしてみましたが、最初はどうやっても片面ではADC周辺部分に部品が載り切らなかったです。 見積もりをWeb上で試してみたところ、やはり両面実装になると、値段はそれなりにアップしてしまいます。 それで、セラコン、チップ抵抗を0603パッケージから0402に一部変更して、なんとか片側に載せきりました。

電源プレーンは、ビアもない空間がかなり広がってしまっています。最初は最低限の幅でレイアウトしていましたが、 考えてみれば、その下には配線層があるので、できるだけベタにしたほうが良いのかな?と思い、面積を広げました。

また、40MHzのクロックラインもなんとなく周りをGNDの配線でガードしてみました。 トップ面のGND塗りつぶしも試してはみましたが、あまり美しくないのでやめました。

ADC基板

上にある80ピンのコネクタがZ-turn boardと接続するためのものです。電源は+5.0Vと+3.3Vが供給されていますが、 今回は3.3Vのみ使用しました。基板の左と下にはSMAメスのライトアングルコネクタがあります。 基板右側がヘッドホン端子です。ほぼ真ん中にある45度傾いているICがLTC2292(ADC)になります。 データシートに記載されている基板レイアウトは、ADCは傾いていませんが、 その代わりにADCへの入力が傾いています。結局は同じようなレイアウトになってしまうものですね。

無駄に何も部品がない空間があるように思いますが、肝心の信号入力部をできるだけ直線になるように配置した結果、 こうなってしまいました。BPFに使っている部品が0603なので、これも長さを食っています。 これでも一応10cm角には入るので、とりあえず良しとします。

これから基板の製作と実装の見積もりを依頼します。 実装も以来できる業者として、PCBCARTElecrowあたりを考えています。

ADC基板のRF入力部分

前回、SDRの実験用基板について記載しましたが、 やっとRF入力についての回路図が大体できたと思います。

RF入力回路図

我ながらごちゃごちゃして見にくいです。1枚に詰め込みすぎ。

図面の上半分が、ADCの入力の回路です。 片方は70-90MHzのBPFを通し、RFアンプ、RF balunを通して差動入力されています。こちらはFM用です。 RFアンプのデータシートを見てみると、一般的にはLNA(Low Noise Amplifier)を通してから、 このアンプに信号を入力するようです。ただ、Interfaceの特集記事ではLNAは使用しないで実現していましたので、 FM程度の帯域だったら問題ないのかもしれません。

もう一方の入力は、シングルエンドモードで使用し、かつRFアンプを使用するパスと使用しないパスをジャンパで選択できるようにしています。 ジャンパでRF信号を通すのは少し気が引けますが、こちらはAM帯域をターゲットするので、 まぁそれほど高速性は要求されないから良いでしょう。

ADCの入力インピーダンスは、データシートによると100Ω以下とするように記載されていますが、 どちらの入力も基本的には50Ωに揃えてあるつもりです。 RFアンプは入力も出力もインピーダンスが50Ωとなるデバイスです。

また、SENSEピンはジャンパにて2Vp-pか1Vp-pかを選択します。

図面真ん中左側にあるのは、ADCのクロック生成部です。 TCXOから出力される40MHzをCDCLVS1102で2つに分岐します。片方はADCのCLKA,CLKBに入力され、 もう一方はコネクタを介してFPGAのCCピンに接続します。ADCからのクロック出力は無いためです。

2017/2/20追記:当初予定していたTCXOは2.5ppmのものでしたが、 digikeyでは在庫がなくなっているため、 ちょっと怖いですがMEMSの5ppmのクロックに変更しました。 お値段もそれなりにアップしてしまいました。

図面下側はADCの電源部です。VDDはMax 3.4V、Typical 3.0Vです。LDOで3.3Vから3.0Vを生成し、 かつ生成された3.0Vと3.3Vから使用する電圧をジャンパで設定できるようにしています。 クロックが3.3Vなので、VDD=3.0Vで動作させるのはどうかな、という懸念があるためです。 この回路全体で使用されるのは最大で150mA程度と想定されますので、300mA出力のLDOを選択しています。

この回路を作成していたら、オーディオ出力も載せたくなってきました。 最終的にFPGAでSDRを実装したら、そのまま音を出してみたいですしね。 元々の予定だと、この程度の回路で基板を描くつもりでしたが、 オーディオ部分も回路を作成しようと思います。

回路作成すると、いろいろと欲が出てきます。

ADC基板の構想

FPGAと基板を接続して、簡単なSDR(Software Defined Radio)の実験をしてみたいと 思っています。Interface 2015年7月号に触発されました。

上記記事では、LPC-Link2を使ってAMとFMの受信を行っています。 私も、まずはマイコン上でソフトウェア処理する前に、一回ADCデータをパソコンにすべてダンプして、PC上で オフライン処理をしてみようと試みたことがありました。 実際にLPC-Link2で実験してみたところ、USBの転送速度からして、10M sample/sec程度が良いところ、という印象でした。

上記特集ではこの程度のサンプリングレートでAM/FM復調を行っていますので、まぁ十分なのですが。

単に基板を作ってみたいという個人的趣味が先行しています。

それで、Z-turn Boardに接続する、ADCとUSB3.0が搭載されたボードを作ろうと目論んでいます。 今はいろいろと基本的な部品の選定を行っています。ある程度固まってきたので、記録しておきます。 随時追加予定です。使用する部品は、Elecrowあたりで実装することを考えて、digikeyやmouserで容易に入手できそうなものを選びます。

また、ADC周りの設計は完全に素人なのですが、自分なりに調査した結果、AM/FMならばとりあえず、 BPF->RFアンプ->RFトランス->ADCという信号の流れで良いのではないかと考えました。 ADCは差動入力なので、RFトランス(Balun)にてシングルエンド信号を差動に変換します。 ただし、RFトランスは低周波数(1MHz以下)あたりでは性能が悪化するようです。それで、FMについては上記信号経路とし、 BPF, RFアンプ, RFトランスについてはジャンパでそれぞれバイパスできるようにします。 また、ADCについても、ジャンパにて差動モードとシングルエンドモード両方で使えるようにしたいです。

実際に上記雑誌の特集では、AMについては一切外付け部品を使用せず、アンテナを直接ADCに繋いでいます(ADCの前にLPFが入っていますが)。

2017/2/17追記:上記のようにジャンパで信号パスを選択することを想定しましたが、Linear Technology LTC2292CUPは2チャンネル入力があり、 かつ比較的安価なので、こちらを使用してFM, AM用としてそれぞれ使おうかと思います。 また基板は、ADCが乗ったものと、USB3.0が乗ったものを別々に製作しようと思います。 ADCとUSB3.0基板では、必要なPCBの層数も違いますし、基板製作に失敗したときのダメージも分けたほうが小さいので。

  • RFアンプ:BGA2818 (6-TSSOP)
  • P1dB: 4dBm, Gain: 30dB, 雑音: 3.3dB
  • RFトランス:MABAES0060 (RF1:1 Flux Coupled Transformer, 0.3-200MHz, 1:1 impedance)
  • digikeyにて297円. 画像がいかにもトランスです。果たしてElecrowで実装できるのか?
  • データシート
  • ADC:LTC2292CUP (12bit, 40M sample, 64-QFN)
  • ADC:AD9235BRUZ-40 (12bit, 40M sample, TSSOP-28) こちらは対象外に脱落
  • USB:CYUSB3014-BZXC

(本当はLVDS出力のADCが良かったのですが、結構お高いので、まずはできるだけ安いもので実験してみようと思いました。 ただし、このADCはレジスタ設定のようなものが無い代わりに、ピンの電圧などで動作が変わるという奇妙なデバイスです。)