Mbed上のARMマイコンでDSP遊びを!【2021.6.25】




 もうすでに一か月くらいHPの更新をしていなかったのは、掲題のような遊びにハマっていたので、とても余裕が無かったという理由からです。少しまとまったらHP記載を開始しようと思ってはいたのですが、実験が面白いのと、あとからあとから検討アイテムが出てくるので、このままでは、いつになってもHPに戻らずじまいになりはしないかと心配し始めました。一方、一か月も前の出来事など、この頃とみに記憶力の衰えた脳みそでは、とっても思い出すことができないので、少しずつでも記録を残すことを開始しました。

 実はDSPというかSDRというか、ディジタル処理の「自作」に関しては、ちょっとやそっとでは実用的な物は自分じゃ製作できないと諦めていてました。いままで、TRX-305、DSR-3、Redpitayaと、出来合いのボード(あ、SDR-3はKitで、違うと言えば違うが、これは単に部品マウントしただけで、中身は既製品だし)にアナログインターフェースをつけて、自作機でござい・・とやってきました。ま、それでも、Redpitaya-16等は、けっこうな高性能でしたから、それはそれで面白く遊んでいました。

 ただ、最近は、そうしたブツもいいのですが、少し、処理の中身にも少しは踏み込みたいなとの思いがあって、なにかいいものないかといろいろ物色していたのです。そうした中で、昨年末に発売されたTr技術1月号に、DSPの啓蒙の大家である、三上さんがArmマイコンを使ったダイレクトサンプリングSDR(中波帯AMですが)の記事を発表されて、これには一気に興味がわきました。三上さんのことなので、洗練された中身で、ソフトの更新にまで自分でもトライできるかもしれない・・・・と思ったのです。結果、普段は買わないで立ち読みで済ますTR技術を久々に5か月連続で購入しました(笑)。

 中身を見ると、C++でクラスを用いた洗練されたプログラムで、期待どおりの素晴らしいものでした。しかしながら、ソフト音痴の私にとっては、これだと、ほとんどバイナリファイルを実行しただけで終わっちまうかもしれない・・・また挫折か?と思い至るにそう時間は掛かりませんでした(苦笑)。中身を自分でいじれる方法は他にないかなぁ?と思い悩んでいるときに、偶然寄った秋葉のヨドバシの本屋で、またまた三上さんの著書「ARMマイコンで学ぶデジタル信号処理」を見つけました。





 ページをめくると、簡単な事例から順を追ってDSPの基本的な処理を学べるように構成になっていました。なので、即買いで読み始めたのです。この中身は初心者にも手軽にDSPを体験できるように構成されており、大変に懇切丁寧に書かれています。しかし、よく見ると、Weaver変調器やヒルベルト変換を用いた周波数シフト等(って、まさにSSBの変復調じゃね!)、SDRにも応用可能な気がする事例も載っていていて、なかなか「味わい深い」内容になっています。

 一方、ハードウェアはというと、STmicroの実績のあるマイコンSTM32F446REを使っています。クロックが180MHzで浮動少数点コプロセッサありで、1クロックで加減乗算ができ(除算は14クロック)、2CHの12ビットのAD/DAを1チップに搭載しています。昔、遊んでいたTMS32C6713というDSPに比べるとさすがに見劣りしますが、このボードは2K円で購入できて、Mbedというネット上の開発環境が無償で提供されているのも、ナイスな点ですね。開発環境のローカルPC上での維持は、私のようなソフト開発なんてやったことがない「超のつくドシロート」には、面倒以外何者でもありませんから。ハード能力的には、このマイコンであれば、アマチュア周波数帯のダイレクトサンプルは到底無理でも、ローIFやゼロIFのI/Q処理ならば、十分に可能な感触だったので、まずはそこからスタートしてみます。






 さて、機材はそろったので意気軒高に始めたのはいいのですが、ドシロートゆえになかなかハードルの高い壁がありました。その最たるものが、上記の書籍の全編を通じて、C++の「クラス」を多用したプログラムになっていることです。私は、Cでさえもきれいなコードを書けないのに、さらにきれいな構造化されたプログラムなんて、理解するのに精いっぱいで、自分で書ける気がしません。なので、書籍の題材からは

・アナログ入出力の基本プログラム(昔、6713DSKでは”THROUGH”プログラムと言っていたA/Dして即D/Aする割り込みハンドラ)に、必要な処理を書き込んでいく。

・クラスにこだわらず、プログラムの見た目は「汚くても」自分に取ってやりやすい、「処理を関数内に閉じ込める」方法で処理の進みをシーケンシャルに書いていく。

 ・・・ことで、コードの体裁にとらわれず、DSP処理された後に得られる特性を実感していくことに重きを置きました。私としては、コードをきれいに書いて、誰からも読みやすく、また、時間が経ってもわかりやすくすることよりは、そのコードが実現する特性確認を早く行うほうが重要なので、C++特有の流儀に乗らなくてもいいかと思ったのです。要するに、C++コンパイラで、きったねーCのコードをコンパイルさせるというドシロート行動を取るわけです(大笑)。なので、私の書いたきったねーコード全体をアップするような勇気のあることはやりませんので、悪しからずということで。

 さて、前置きがいつにも増して長いので、ここらでまずは本体のインターフェースについて触れておきます。




インターフェースの改造




いつものごとく基板カット法で固定したの図

上にはQSDのFTS3253とOPAが実装されている(後述)
下には同QSEを実装する予定



 上図は三上本のP12にあった1入力1出力のインターフェースを、これではI/Q処理ができないので、2入力2出力に改変した回路です。OPAをオリジナルの一個入りパッケージのものから二個入りに、また、出力の一次のLPFはFsを変えると邪魔になるので、除外してしまっています。オリジナルは全編でFs=10kspsにほぼ統一しているようなのですが、これでは思うような実験ができませんから。ナイキスト周波数~Fsのイメージの除去に関しては、三上本では時間波形をオシロ等で観察することを想定しているようですが、スペアナやネットワークアナライザで見ればあまり考える必要がなくて、そのうち実機に仕上げる必要性が出てきた時点で、この領域の除去のためのアナログ処理は考えることにします。また、三上本に掲載された多くの事例では、出力時に4倍オーバーサンプルで出力フィルタの簡略化を図っていますが、ここでは、このオーバーサンプル処理は必要が無い限り実施しません。

 さて、初回にしては長くなりそうなので、今回はこの辺で。


<DSP遊び開始!> 【2021.7.20】

 あっという間に時間が過ぎていきますので、こちらも少し進めておくことにします。

 前回に、Nucleo-F446REボードとそのアナログI/Oについて書きましたが、実際の動作をさせたときの特性確認の方法について考えておきます。三上本では、何らかの処理をした後の応答波形を簡易なデジタルストレージオシロか、スペアナ(これもNucleo-F446を使って作る)で観測して動作を見るように書かれています。これだと、12ビットのA/Dなので、特にスペアナの場合はダイナミックレンジにちょっと不安がありますので、ここでは、三上本の手法を取らずに、使い慣れたAPB-3をフル活用しようと考えました。





測定系


 上図に基本的な測定系を示します。このDSPで遊ぶのは、フィルタ、信号発生、ミクサ、変復調等ですから、スペアナとネットワークアナライザがあると大変便利です。信号源には2-トーン信号もあれば、ほぼ完ぺきでしょう。今回は、ベースバンドからせいぜいLo-IFで遊ぶので、私の所有する測定器から、APB-3を選びました。これは測定ダイナミックレンジが広く、一般のスペアナではLocalの近傍C/Nが悪いためにまともに測定できない、AF帯の測定ができますから大変に重宝します。図中にSWと書いてありますが、これは信号経路切り替えのために示したのであって、実際にSWがあるわけではありません。

 また、Nucleo-F446は2入力2出力の構成で用いています。この入出力には、直交変調器や直交復調器が接続されて、SDRを構成することとなります。外部にこれらを接続する場合は、直交した信号源が必要になりますが、それはおいおい書いていくことにします。

 次はプログラムの作成になるわけですが、これは最初に書いた通り、かなり変則的な方法によっています。先にも書きましたが、この開発ツールおよびC++に慣れるまでは、ネタ本である三上先生の「Mbedを使った電子工作プログラミング」「Armマイコンで学ぶディジタル信号処理」にあるようなクラスを多用した書き方はせず、従来のCライクな関数主体の書き方になっている点がいかにも素人的です。

 また、Mbedのプロジェクトですが、下図を見てください。最初は、実現したい機能ごとにプロジェクトを作っていこうかと思ったのですが、似たようなプロジェクトが乱立し始めたので、ベースとなるプロジェクトを作って、そこに必要なヘッダーファイルを収めて置き、機能ごとにヘッダーファイルやMainのCPPファイルの「中身」を書き換えて実行させることにしました。




プロジェクトの構成


 例えば上図でDoubleChannelADDAというプロジェクトは、入出力がそれぞれ「最大」2チャンネルを用いるDSPプログラムのひな型で、必要なクラスやヘッダーファイルが揃っています。このプロジェクト内で、IFおよびベースバンド処理の変復調機能をプログラムすることができます。

 変復調方式を変えても、変わるのはMainのなかの割り込みハンドラ内の記述とフィルター類を規定する.HPPファイルの中身(係数含む)が主なので、Main.CPP、IIR.HPP、FIR.HPPの3つのファイルを書き換えればたいていの場合は動いてしまいます。なので、ファイルは上図のように残しておいて、中身をそれぞれテキスト形式(メモ帳で十分)で、実現する機能ごとにまとめて残しておくことにしました。これで、ベースとなるひな型(DoubleChannelADDA)の各ファイルに「書き込め」ば動作させることができます。ま、この方法はきわめて変則的ですが、慣れると簡便なので嵌ってしまいます(笑)。

 次に簡単なプログラムを走らせてみます。前に書いたように、三上本の真骨頂である、クラスを用いたきれいなコードからはかなりかけ離れた書き方ですが、ま、小さい規模なら、どうとでも書けるので、気にしないことにします。




DSB生成プログラム

 includeされる.HPPファイルはオリジナルと変えていません。IIRフィルタの係数は三上本に連携するIIRフィルタ設計用のツールを使い、カットオフは200Hzの6次のIIRのHPFを計算してあります。入力された信号のDCカットを行って、プログラム内で生成した12kHzのキャリアと乗算してD/Aに出力させるだけです。





入力のIIRフィルタ(DCカット用)




2-トーンDSBスペクトラム


 上記がD/A出力のモニタ結果です。今見ると、若干スプリアスが多いように見受けられます。ま、このあと、アナログ方式ならば、クリスタルフィルターを挿入するので、消えてなくなる----DSPでも同じくSSB生成のFIRフィルタで除去します----ので、ま、目くじらを立てる必要はないのですが。それから、ナイキスト周波数(Fs/2)からFsまでの間の折り返しはなんらかの方法で除去する必要があります。IF=12kHzと考えるとアップコンバージョンして、ハイフレのパッシブフィルタ(XF)で除去するのが常套手段となります。お約束のごとく0次ホールドの影響で高域が減衰していますが、ここでは、IFとして12kHz近辺を使うので、補正はしていません。

 こんな感じで、割り込みハンドラAdcIsr()の中に必要な処理を書いていけば、その結果がD/Aに出力されます。必要に応じて途中の状況を別CHに出力したり、変数の値をシリアルモニタで表示させたりすれば、たいていのデバッグはできると思います。

 Mbedの使い勝手ですが、コンパイルは比較的速く、コンパイラ本体はサーバー上にあるにも関わらず、あまりストレスを感じません。Arduinoなんかだと、コンパイルも書き込みも「激おそ」なのでストレスがありますが、Mbedはそんなことがないです。シロートの私にでも心地よく使えるので、気に入ってしまいました。



<SSB変調3題> 【2021.8.17】

 だいぶ間が空いてしまいましたが、少しづつ進んでいる経過を残しておこうと思います。内容的には2か月くらい前の話で恐縮ですが、とりあえず纏めておかないと本当に忘却の彼方になりそうなので、重い腰を上げました。

①まずはフィルタ方式SSB

 前回はとっかかりでDSBができるところまでやりました。これに急峻なフィルタをかければSSBができます。これはクリスタルフィルタを使った方法と同じですが、この程度のDSPではいきなり高周波のSSB化は無理ですので、必然的にローIFでやることになります。もちろんFPGAベースのロジックと高速DAを使えばこの限りではないですが、今回のスコープからは外れることになります。

 ということで、フィルタの設計に行きます。以下は完全フラットな帯域が2.1kHzの中心周波数が12kHzのBPFです。このパラメータは、実行可能時間から決めたFIRフィルタの次数、減衰域と通過域のシェープファクタ、帯域外減衰量等を勘案して決めています。




設計値




実際のBPF特性


 Fs=48kspsで帯域が2.1kHz、帯域外減衰量が-60dB以上(-67dB)、シェイプファクタ1.3が250次で作成可能です。一応、設計通りに動いていることも確認しています。この次数だと、20.8μS内にぎりぎり実行可能になります。このように構成エレメント毎に動作を確認するために任意の場所でD/Aしてスペクトラムをみるのは面白いデバッグ法です。これは、時間領域(オシロ)だと折り返しの信号とごちゃごちゃになるので簡単には行きません。そういう意味で、ダイナミックレンジが大きく、C/Nが抜群なので、オーディオ帯までしっかり狭帯域の測定できるAPB-3は「宝物」のような測定器です。最近のガジェットには及びもつかない(もっとも値段が違いますが)素晴らしい逸品ですね。Ojisankoubouには感謝しかありません。

おっと、脱線。これと、前回示したDSBのキャリア周波数を12kHzから13.55kHzに変更して、LSBを取り出したのが以下の図です。




SSBのスペクトラム


 こんな感じに、いにしえのフィルター法で、SSBを作り出すことができました。ちょっと3次のIMDが-60dB近く出ていますが、レベルを下げれば消えてなくなります。キャリアサプレッション、サイドバンドサプレッションも-60dB以下なので、問題はないと思います。24kHzの倍波、あるいはFsの折り返しの成分が出てきますが、ローIFで生成したSSBはアップコンバージョンする際にフィルタリングで抑圧できますので、気にしなくていいと思います。

②フェーズシフトタイプ

 最近では、かなりの人が知っている「ヒルベルトフィルタ」(笑)を用いたフェーズシフトタイプのSSBを作っておきましょう。構成を以下に示します。




フェーズシフトタイプの構成


 これはだいぶ一般的になってきているので、説明は省略します。このHP内でも、大昔にTIのDSP、あるいはちょっと前にGNURadioとRedpitayaでもいじっているので、探して見てください。

 実は、ヒルベルトフィルタを作るには、できる限りFsが低い方が有利です。というのも、音声が通過する帯域で90度の位相差を得る必要があるので、BPFを使ったヒルベルトフィルタの高域カットオフは Fs/2-音声帯域下限 としなければならないので、広い帯域での設計が不可欠となり、FIRの次数も多くなってしまって、DSPリソースが非常にもったいないです。なので、低いFsでヒルベルトフィルタを作り、生成したSSBをアップサンプルして、Fsの折り返しを簡単なフィルタで削除するのがいいのでしょう。

 そうは言っても、今は「お勉強」ということで、ちょっと無駄なことにもトライしておきます。





設計例


 帯域内リップルは、キャリヤ&サイドバンドサプレッションの劣化に直結しますので、できる限り小さくする必要があります。次数を上げればいくらでも小さくなりますが、それはDSPの処理リソースで制限を受けます。今回は最大限頑張って300次ということでやってみます。しかし、こんなFIRでも帯域制限は全くできないので、広い(音声帯域以外)帯域で振幅フラットにするのは、本当にもったいないと思います。

 考までに、A/D とD/Aの間の割り込みサービスルーチンを書いておきます。また、高速化FIRのプログラムも併記しておきます。三上本の配列シフトによるFIR計算法では処理時間が1.8倍くらいになるので、ここまでの次数のFIR処理は無理です。




位相方式SSB生成プログラム

注:アンダーバー_が見えずらいですがご容赦を!




高速FIRプログラム

以前TIのDSPをいじっていたころのものと同じ。xn:入力 hk[ ]:FIR係数 Buff_[ ]:高速計算用ダブルバッファ
*index:ダブルバッファ用ポインター length:FIR次数 です。
動作を追っかけると面白いですよ。


 こんな感じに割り込み毎に一連の処理を一気に行っている単純なプログラムです。詳細は省きますが、処理の進みが伝われば私はそれで十分と思うので、「コピーすれば動く」形でのUpはしません。で、実際に動かしたのが以下の図です。




フェーズシフト方式のSSB発生


 若干のスプリアスもありますが、まぁ-60dB以下なので、とりあえずよしとします。フェーズシフトタイプの場合、帯域制限する要素が皆無なので、処理時に生じるスプリアスや折り返しが抑圧できにくいので、あまりオススメの方法ではありませんね。ただ、これも16ビットだと、かなりまともになるのですが、このレベルのµPでは仕方がありません。

③Weaver方式のSSB発生

 以前にも、GNU RadioとRedpiytayaで説明したときの図があったので再掲しておきます。DSPリソースを食うヒルベルトフィルタを用いずにSSB発生ができる方式として、Weaver方式は魅力的です。




Weaver方式構成図



 構成上は面倒「そう」なエレメントが並んでいますが、2つNCOはSin/Cosが同時発生できるので、バルキーではないし、LPFも2つ必要となりますが、これは、極めて急峻な減衰特性を要求されるので、IIRで構成する必要があるのですが、かえってFIRよりは実行時間が少なくてすみます。なので、トータルで考えるとDSPリソースがこれまでの方法より格段に少なくてすみます。 計算&実測してみると、この割り込みハンドラ内実行時間は10µSかそこらで48kspsの処理時間(20.8μS)に対して半分程度なので、余裕たっぷりの動作です。例えば、300次ヒルベルトフィルタの実行時間は18μS以上にもなり、他の処理余裕が殆ど無いのに比べると、IIRでの処理は余裕があるので、他の処理も実行できそうです。




帯域制限IIRフィルタの設計



 そのIIRフィルタの設計例は上図の通りです。1.3kHzまで通過させて、キャリア周波数の1.5kHzではできる限り減衰させる設計です。これで、通過帯域は2.6kHzになります。

 そのあとは、なんのことはありません。愚直に、構成図の通りの計算を実行しているだけです。なので、面白くもなんともありません(笑)ので、ソースは省略します。先のソースを見れば雰囲気はわかると思います。。




Weaver方式スペクトラム


 出てきた信号のスペクトラムが以上です。なんだか、いままでの方式中では一番きれいなスプリアスの無い形になりました。念のため、オーディオ2-トーン入力を無信号にして、1.5kHzキャリアの漏れを見てみましたが以下の通り問題ないようですね。カーソルの位置が帯域内キャリア(1.5kHz+12kHz)の位置を示しています。




帯域内キャリア漏れのない様子



<ゼロIFのSSB受信方式二題> 【2021.9.17】

 なんとも月に一回の更新頻度になってしまいました。ネタは4~5個はあるのですが、UPが追いつきません。コロナの話を止めて、こっちを更新しろ!と言われそうですが、ま、コロナ話も重要なので、時間の許す範囲で書いていこうと思っています(笑)。

 さて、変調の次は復調ですが、いままで、Low IFでやってきたので、信号経路を逆にすれば、Low IFの受信機はできてしまうので、ま、それではつまらないから、ゼロIFでの処理を試してみることにします。よく考えると、SDR自作で最初に作ったブツもゼロIFでした。この方式では直交ミクサが必要になるのですが、まずは大昔に作ったこいつを使って、実験を開始することにします。





ゼロIF受信機の構成




大昔に使っていた直交ミクサ


 直交ミクサの形式ですが、上記のような①大昔型のアナログSWを使ったものの他に、この界隈では極めて有名な②直交サンプル復調器(QSD)を構成するのが容易なFST3253や、③アナログDBMとして使いやすいSA602も適用できるようにしてあります。いずれのタイプも低雑音のOPAで20dBばかり増幅しておく必要があります。なにせ、DSPの分解能が12ビットですから、信号処理ができるレベルまで増幅してあげる必要があるわけです。

 さて、まず最初はヒルベルトフィルタを使ったSSB受信に行ってみます。今回はゼロIFということなので、思いっきりFsを下げてしまってFs=5kspsとしてみます。ただ、Fsを小さくすると、復調時の折り返し成分を抑圧できなくなるので、ほどほどにしないといけません。5kspsだと、実際には復調後のアナログフィルタでは、折り返しがほとんど抑圧できないので、あくまでAPB-3によるスペアナ観測のみの実験になります。仮に本気で復調した信号を「聞きたい」なら最低でも15~20kspsくらいはないと、あるいはインターポレーションでFsを上げておかないと、後置する簡単なアナログフィルタで折り返しが抑圧できないので耳障りです。

 ということで、かる~~くヒルベルトフィルタを作っておきます。今回はI/Q入力なので、FIRが二本必要になるのですが、帯域を広げると、途端に要求される次数が増加するので、それを避けたいという思惑もあります。48kspsだと、多分250次くらいは必要になって、さらに二本必要ですから、合計500次は多分計算時間が多過ぎて動かないはずです。で、作ってみたのが下図のFIRです。


 


ヒルベルトフィルタ設計例


 Fsが低いので、上図に示すごとく、60次程度で十分な特性が得られます。振幅偏差が、もう殆どゼロですので、まったく問題は無いでしょう。位相偏差は、設計上は解らないですが、殆ど考えなくてもいいレベルだと思われます。





主要な処理部


 上図はA/D、D/Aの割り込みルーチン内処理です。直交ミクサ出力のI/Q信号を二系列のヒルベルトフィルタを通過させ、Qチャネルは30タップ目のデータを取り出してきて、その後加減算すればSSBが得られます。





無信号時復調スペクトラム(Si5351をローカルに使用)


 これが、無信号時の復調スペクトラムですが、ちょっと雑音というか、微小スプリアスが多くて機嫌がよくありません(苦笑)。こいつはSi5351に由来するのかと思ったので、AD9952-14ビットDDSに変えてみました。





無信号時復調スペクトラム(AD9952をローカルに使用)


 しかしながらあまりスペクトラム上は改善された様子も見られず、なんだか一気に興味を喪失していきます。Low IFの変調器の場合も、なんとなくスペクトラムがあまりきれいではなかったので、その後遺症もあって、ちょっと先に進める元気が出なくなりました。





復調スペクトラム(AD9952をローカルに使用)

 
 なので、とりあえず、-40dBmの入力をRFトップから入力して、様子を見たのが上図になります。Fs=5kHzのN倍の所に折り返しが見られます。まぁ、それなりに復調はされているようです。そこで、逆サイドバンドの耐力も見たのですが、これは-39dBというところです。どうも、この直交ミクサのバランスが悪いのか、いろいろいじっても、これ以上は改善しませんでした。

 おまけにヒルベルトフィルタでは、帯域外減衰量が稼げないので、「選択度という特性」を持ち得ません。なので、ここで、これ以上足掻いても、得るところは少ないと判断して、この方式はここで、切り上げることにします。


 次に本命の複素BPFを用いるSSB受信機を考えてみます。構成に関しては最初の図そのものですが、さすがに、大昔型の直交復調器は卒業して、流行りのQSDで行ってみたのですが、ふとした理由でDBMのSA602を使った形にしてみることにしました。顛末は後述します。まずは、その様子です。





周辺回路とNucleo F446ボートの様子


 このボードの左側にはFST3253を用いたQSD、右側にはSA604×2を用いた直交復調器を作り込んでみました。いずれも実験ができるようにしてあります。FST3253は、聞くところによると、経時故障が多いらしいので、ソケットで取り外せる構造にしてあります。一方、SA602の方は何の変哲もないミクサーを2個で構成したもので、回路図は以下のような当たり前のものです。





SA602を用いた直交復調器


 SA602の入力は、I/Qチャネルを独立に必要としない多くの用途では、「I/Qチャネルをそのまま結合」してしまって受信入力とし、直交ミクサーとして働くように、シングルエンド入力にしています。真面目にやるなら、トランスを用いて差動化するほうがいいのでしょうが、ま、必要があるなら、ソフトの評価は済んだ後に行えばいいと思いました。後段のオペアンプには、ゲイン調整のVRをつけています。これは、I/Qの振幅バランスを取るために必要で、これは逆サイドバンドの抑圧特性に直結します。できるならば、位相の調整もできるとよかったのですが、これについては、やり方を含めて別途考えることにします。

 ローカルに関しては、いままで使っていた74AC74の1/4分周回路による位相差生成回路を止めて、以下のようなバラック的に作ったSi5351の発振器を使うことにします。





Si5351 Quadrature OSC


 これは90度の位相差を持つ2信号を発生できる便利な発振器になっています。Arduino Prominiを用いて3.3V動作させていて、I2CのSi5351、OLEDディスプレイともに直結なので、非常に便利です。ロータリーSWで12バンド(書き込み)を切り替えられます。また、100ppr(パルス/回転)のロータリーエンコーダで、周波数可変もできるようにしています。今のところ、可変ステップは100Hzで、SSB/AMのいずれにもギリ使えるようにしてあります。

 肝心の90度位相差生成の方法は、JF3HZBさんのここの情報を元に、Si5351のヘッダーファイルを書き換えています。2チャネルの周波数設定時に必要な位相差設定値を追加書き込みしているだけです。





90度位相差のある信号の様子



 上図のほかに、リサージュも見てみましたが、正方形に近似できるので、90度位相差が実現できているようです。

 これらを用いて、受信機を構成してみましょう。その前に複素BPFについて少々書いておきます。詳しくは専門書に譲りますが、

・FIRのLPFの各係数H(k)に、周波数シフトのための複素積(Real側:Cos(2π・k・Fshift/Fsample) Image側:Sin(2π・k・Fshift/Fsample))を乗算すると、シフト周波数を中心に上側はLPFをシフトした特性、下側はLPFをゼロ周波数で反転した形のHPFの特性を持つBPFのFIR係数が得られる。

・Real側とImage側の複素BPFは通過帯域内で90度の位相差が発生する。

という性質を利用すれば、このReal/Image用に作られたBPFを、帯域制限付ヒルベルト変換器のように扱うことができます。ということで、まずは、ベースのLPFを作ってみます。





複素BPF用ベースLPFの設計例


 上図は300Hz~2700Hzを減衰ゼロで通過させる複素BPFを作るためのベースLPFです。0~1.2kHzを減衰ゼロで通過させ、1.5kHz離れたら65dB以上の減衰を実現させています。この急峻さをFIRで作るには、次数を大きくしなければならず、ここでは250次としています。I/Q両チャネルで同じ次数のフィルタが必要なので、さすがにサンプリング周波数(Fsample)は20kHzにしています。この受信機では合計500次のFIRをサンプリング周期の50µS以内で実現させています。折り返しの減衰の必要もあるので、サンプリング周波数はせいぜい下げても15kHzが限界だと思います。この点、オーバーサンプリング機能を持つ専用A/Dが使えれば、こんな心配は全く無用なのですが。無いものねだりなので、ここでは諦めます
 





複素BPFを用いた受信機のプログラム



 毎度同じようなものなので恐縮ですが、2CHのA/D入力に対してDCカットのためのHPF(6次)をI/Q信号共に通過させ、そのあとをそれぞれ、I/Q用に係数を計算した複素BPFに通過させて、その出力を加算すればSSBの復調が一丁あがりということになります。先のヒルベルト変換器を用いた受信機と殆ど同じ構成なのが解ると思います。





複素BPFの帯域特性


 さて、ここでうるさいほどコメントしてきた複素フィルタの帯域特性を実測した結果を上記に示します。先に説明したようなBPF特性になっていますね。これは、複素BPFの出力をAPB-3のスカラーネットワークアナライザ機能でスイープさせた結果です。このフィルタがI/Q用にそれぞれReal/Imageの係数を持ったFIRで構成される訳です。

 このような処理でSSBの復調ができるわけですが、直交ミクサーにゲインのあるSA602を用いて、さらにトップに20dB程度のアンプ(BGA616)に6dBのATTを後置して感度を測ったのが以下の図です。ヒルベルトフィルタを用いたRXと比べると、変なスプリアス受信がかなり減っています。





 復調スペクトラム

Fs=20kHzなのでN*20kHzとその周辺にイメージが現れる

 これは、入力が0.6μVrmsでSINAD=20dBも得られていますが、これは折り返し抑圧のためのCCITTフィルタを入れています。なので、通常のSINADで評価するとだと3dB程度悪くなります。いずれにしても、十分な感度を得ることができます。聞いた感じでは、他の私の自作機と似たような感度を得ることはできました。また、逆サイドバンド抑圧は52dB程度は実現できましたが、OPA回路のバランス調整だけでは、これ以上の改善はできませんでした。

 最後に、先に設計したフィルタは若干帯域が広いので、-6dB帯域が2.4kHz程度になるような、ベースLPFの例を下記に示しておきます。これだと、かなり「かぶり」を抑えることができてFBです。





狭い帯域のベースLPF


<I/Q DEMOによるAM受信とI/Q MODによるSSB生成> 【2021.10.2】

 さて、SSB受信ができたので、次は同じ構成でAM受信をしてみることにします。

 処理の流れを以下に示して、それに沿ってソフトモジュールを組み合わせていきます。




AM受信の処理


 I/Qチャネルのベースバンド帯域制限のあとは、その包絡線(√(I^2+Q^2))を計算して、そこからDC成分を差っ引くことになります。これは、まさにAM信号の数式表現から変調成分を抽出することに等しいですね。ここはあまり説明は必要ないでしょう。

 入力のDCカットのフィルタは、A/D出力は電源電圧/2にオフセットされていますので、そのオフセット分を取り除くためのフィルタです。HPFでIIRの6次相当でカットオフは50Hzというものです。その次のFIRがメインの帯域制限フィルタになります。以下に設計例を示します。Fs=20kHzに取り、2.5kHzまで通過させます。放送のように高域を延ばす必要もないので、通信用としてはこの程度で十分でしょう。




AM用LPFの設計例

通過帯域は2.5kHzとした


 おっと、SSBではこのフィルタに複素BPFを用いて、I/Qチャネルで90度の位相差を待たせましたが、AMの場合は、包絡線を抽出するだけですから、I/Qで同じ特性のものでOKです。Fsが低いのと、帯域が広く、減衰遷移域も0.5kHzとってあるので、SSBの複素フィルタに比べて次数が少なくて形成できます。片CH150次でトータル300次ということになりますが、SSBに比べて処理時間に余裕があります。とはいっても、何か大きな処理をするという訳でもありませんが。

 次は包絡線の計算ですが、まさにこの数式通りの計算をしています。I/Q成分をそれぞれ二乗してそのあと開平するだけです。




DC抽出用IIRフィルタ


 上図は処理の最後のDCを抽出するIIRです。次数は二次のLPFでカットオフ周波数は0.001Hzにしています。0.1Hzで80dBも減衰しますから、DC以外は通過させません。このフィルタを通過させて抽出したDCレベルを、先の包絡線(√(I^2+Q^2))から差し引いて、AM波を復調するわけです。

 一応、ソースをいつものごとく示しますが、ま、上記の流れをそのまま表しているだけなので、特筆すべき点はありません。





AM復調の処理




復調されたAM変調信号


 上図は1kHzの変調入力で50%変調したSSGからの信号を、ベースバンドI/Q信号に変換(先のQuadlature OSCとI/QMixerで)し、今まで述べた処理を行って復調したスペクトラムです。入力は7.1MHzで-40dBmと十分高いレベルです。復調SINADは40dB程度で、十分クリアです。ただ、音声帯域内にスプリアスが多く、あまり「お気に入り」というわけではありません。AM受信に特化させてギリギリ特性を追い込む気も起きないので、ここは、AM復調の動作を確認したというところで次に移りたいと思います。


 さて、ベースバンドやLow IF における処理の勉強の最後として、直交変調器を用いたSSB生成に触れておくことにします。前回の直交復調器を用いたRXとこの直交変調器を用いたTXとで、簡易な送受信機を作ることができます。実際には、いろいろチューンしなければならない所は多いのですが、世の中を見渡すと、FPGAと高速A/D D/Aを用いるダイレクトサンプリング方式のTRXは、いかにも自作は「手に余る」ので、自作家にとっては、ゼロIFでI/Q信号をオーディオ帯ベースバンド処理する方式がなんとか手が届く領域なのだろうと思います。そういった意味で、基本的な所を抑えるには、これまで書いてきた領域はいい教材ではないかと思っています。





Nucleo F446REと直交変調器

D13はディジタル出力ではないD/Aがつながる


 上図はNucleo F446REと直交変調器を組み合わせたRF帯の基本的なTXの構成ということになります。まず、Nucleo F466REの動作ですが、これは至極簡単です。入力のオーディオ信号を互いに90度位相差のあるI/Q信号に変換して出力するだけです。この実信号を複素信号に変換するのは、すでにここでさんざんいじった複素BPFが使えます。入力の実信号をそれぞれI/Qの複素BPFに通過させればいいわけです。これが、Nucleo F446REのI/Q出力ということになります。

 さて、では直交変調器はというと、これまたDBMとコンバイナーの組み合わせでちゃっちゃと作ることにしましょう。





NJM2594による直交変調器


 これはNJM2594を二個使った簡単な直交変調器です。RFの90度移相は、Si5351のQuadrature VFOに依っていますから、DBMの50Ω側出力をバランス調整用の50ΩのVRを介してハイブリッド結合器で合成しているだけです。当たり前の回路なので、回路図は省略します。以下に7MHzと21MHzの2-トーン変調スペクトラムを示しておきます。





7MHzのスペクトラム




21MHzのスペクトラム


 ここで重要なのは、キャリアサプレッションとサイドバンドサプレッションです。直交変調器がアナログ素子の構成のために、振幅バランスを調整するためのVRを挿入してあってもこの抑圧は簡単には行きません。7MHzの例ではキャリアサプレッションが-48dB、サイドが-43dB程度、21MHzでは順に-42dB、-52dBと、あまり褒められた値ではありません。ネットを検索すると、この辺りはギリギリと調整して-50dB程度のようで、これ以上は何らかのソフトによる補正が必要のようです。

 ま、負け惜しみというわけでもないのですが、この記事のシリーズは、そうした特性をギリギリ詰めるのが目的ではなく、DSP処理の勉強が主目的なので、あまりこだわらないで先に進もうと思います。アナログ部分に依拠するアンバランスはいくら調整で追い込んでも、経過時間とともに崩れるのが必定なので、あまり根を詰めても仕方がありません。

 実は、このような直交変調器をDSPの外部に持つ場合、キャリサプ、サイドサプ以外にも気にしなければならない問題があります。それは、N*Fs周りの折り返し信号(Nは整数)が、帯域外スプリアスに直結するという問題です。これは結構深刻な問題で、この解決無しに「無線周波数信号」を空に放出することはできません。

 いままで、LOW IFの場合やゼロIFの場合のN*Fs周りの折り返しに関してはコメントしないで来ましたが(ここここ、あるいはここで見えます)、実はディジタル信号処理を行う上で避けて通れないものです。ゼロ次ホールドによる減衰も期待できますが、到底完全なもの(無線機のスプリアスという意味)ではありません。ではどうするか?

 一番スマートな解決法は、オーディオ用でオーバーサンプル&帯域制限機能のついているD/Aを用いることです。SDR-3に使われているAudio CodecはTiのTLV320AIC3204で、256倍オーバーサンプルできますので、処理されたオーディオ信号入力のFs周りの折り返し信号は、遥か彼方にすっ飛びますので、単純なフィルタで完全抑圧が可能です。専用のCODECではなくても、dsPICにはこの機能を持つチップもあるので、これを使えれば大きな味方になりますね。Fs折り返しが妨害になることは考慮しないで、信号処理に没頭することができます。

 ところが、現在お遊び中のNucleo F446REのD/Aは12ビットで、D/Aはオーディオに特化しておらず、必然的にそんな機能は持ち合わせて居ませんので、「ばんばん」とN*Fs周りお折り返しが出てきます。今回のFs=20kHzであれば、RF周波数が7.1MHzとかに変換したら、その±(N*Fs)にスプリアスがたちます。これは「変調器」としてはたまったものではありません。RFに変換したら、通常、狭帯域のフィルタは適用できませんから(IFのXFとかで抑圧することは可能)、このような用途にDSPを用いるには、オーバーサンプリング機能付D/Aの採用が不可避となります。

 と、いろいろ書いたところで、今回のトライには、オーバーサンプル機能付D/Aが採用できませんので、極めて泥臭い、アナログフィルタでどこまで行くかトライしてみます。

 



スプリアス低減用アナログフィルタ


 上図は2CHの多重帰還型のアクティブLPFです。Nucleo F446REのD/A出力を見ると、20kHz離れで、基本波に対して0次ホールド効果で-22dB落ちていますので、通過帯域を4kHzとし、18~9kHzあたりで-30dB程度を減衰させようとざっくり作ったものです。これを、I/QチャネルのD/A出力に挿入して、この出力を直交MODに入力してSSB化しようというものです。ディジタルのいいところが失われるようで、あまり気が進まないのですが、とりあえず様子を見てみます。




7MHzのスペクトラム(中帯域)

変調信号は800Hz離れの2-トーンだが、主波もスプリアスも平均化(30回のリニアアベレージ)
によって疑似的な単一スペクトラムのように見える



 これは、先のアナログフィルタを挿入した直交変調器出力です。信号は2-トーンを入力して、RBW=1kHzで30回平均していますので、かなり厳しい測定法です。主波(中心)に対して、下側周波数では-47dBと目標の-50dBに及びませんでした。これは、フィルタの最適化(もう少し急峻に)すれば-50dBはクリアできると思いますが、私の心情的には、あまり乗り気のしない方法ではあります。ま、勉強と思っていて、これを実用化することはあまり考えていないので、この辺で矛を収めることにします。

 さて、Nucleo遊びもかなり進んで来ました。今までには、基本となる変調・復調の実験を行ってきましたが、次は、直交DEMOを用いないで、ハムバンドの信号をダイレクトにNucleo F446に突っ込んで復調するという、ある意味「離れ業」に関して書いてみようと思います。ここは三上さんの本やトラ技を追っていて、一番面白かった部分でもあります。 (続く)