非職業的技師の覚え書き

JK1EJPの技術的検討事項を中心に記録を残します。

Teensy(17)Keiths' SDR用Backpackボードの組立と点灯試験

Backpackボードの概要

Keiths' SDR用Backpackボードを組み立てました。このボードは4.3'' TFT LCDディスプレイの背面に取り付け可能になっており、ディスプレイを含めた各種入出力デバイスとTennsy 4.1とのインターフェースを提供してくれます。

Wiring pattern of Backpack PCB for Keiths' SDR.

Block diagram of the interface functions provided by the Backpack PCB for Keiths' SDR.

Assembled Backpack PCB for Keiths' SDR.
(Only components needed for immediate debugging are mounted.)

当面の動作確認に必要なコネクタを実装しました。イーサネット/USBコネクタ、GPSコネクタ、日付/時刻保持用コイン型電池フォルダ等はまだ実装していません。

部品の調達

Backpack PCB

このPCBはN0CTL局 John Scherer OMがEasyEDAを用いて設計したもので、設計データは下記のホームページに公開されています。

EasyEDAの上記ホームページからJLCPCB社にPCB製作の発注もできるようです。他の方が発注した余り?がeBayに出品されていたため、割高とは思いましたが今回は取り急ぎeBayから入手しました。

ディスプレイ

ディスプレイに描画するためには、提供されるドライバのAPIに対してSDRアプリケーション側から描画コマンドを発行する必要があります。SDRアプリでは特に、スペクトルウオーターフォールを高速に描画するための工夫(更新部分のみのブロック転送等)が必要なようです。描画コードはまだ調べていませんが、Windowsの世界のように標準化されたAPIは組込みの世界(Aruduinoの世界)にはないものと思います。ディスプレイのコントローラが異なればドライバAPIも異なるため、描画コードの書き直しが必要になります。

Keiths' SDRのK7MDL局Mike OM版では2つのコントローラがサポートされています。4.3インチ用のRA8875と7インチ用のRA8876です。ディスプレイ描画コードに足を踏み入れたくない場合は、この2つの中から選択するのが無難です。

しかし、サイズとコントローラの型番だけではディスプレイ選定の仕様として不十分です。例えば4.3インチの場合は、次の仕様を充足する必要があるようです。

  • Display resolution: 800x480
  • Interface: Pin Header Connection-4-Wire SPI
  • Power Supply: 5.0V
  • Touch Panel: 4.3"Capacitive Touch Panel

大手通販でこれらの仕様を全て満たすディスプレイを探すのは至難の業と思います。Mike OMの調達先としてGitHubの下記Wikiに記載のあるEastRising Technology Co.,LimitedのディスプレイをマーケットプレイスBuyDisplay.comから購入するのが安心と思います。

それでも、BuyDisplay.comでは膨大な種類のディスプレイが販売されているため、その中から適切なディスプレイを探し出し、適切なオプション仕様を選択するのも困難です。型番を指定してくれれば簡単になるのですが、なぜか型番の指定は長らくありませんでした。「お好きなディスプレイでDIY」ということでしょうか・・・。

しかし、Keiths' SDRのフォーラムで「間違えて解像度480x272の4.3"ディスプレイを購入してしまった。何を買えばいいんだ!?」との旨の投稿があり、Mike OMがWikiに下記リンクを乗せてくれました。ベース型番はER-TFTM043A2-7Rとなるようです。

上記のフォーラム投稿を見た時に当局は既に4.3"ディスプレイを購入済みでした。悪い予感がしたため、発注伝票を再確認したところ解像度の記載はありませんでした。製品ホームページのDescriptionの詳細説明の中に小さい字で解像度480x272の記載がありました。投稿者と同じ間違いをしていました。

間違えた製品名は「4.3 inch TFT LCD Display Capacitive Touchscreen
w/RA8875 Controller」で解像度の表記無し。他方、正しい製品名は「SPI 800x480 4.3'' TFT LCD Module Display Touch Panel Screen RA8875」です。おそらく低解像度480x272の製品が初めに出て、高解像度800x480の製品が後に出たため、区別する必要のなかった前者の解像度の説明が控えめなのでしょう。

間違えた理由はもう一つあります。製品ページのディスプレイのベゼルの色は、後者がシルバーで前者は黒です。そしてMike OMの投稿写真のベゼルは黒色でした。購入してから分かったのですが、ディスプレイのベゼルを含めた筐体の色はシルバーで、その表面に設置するオプションのタッチスクリーンのベゼル部の色が黒なのです。製品ページにタッチスクリーン付きのCGを乗せるかどうかの違いに惑わされました。

Display appearance with and without touchscreen.

フォーラムには「BuyDisplay.comと交換について相談してみては」とのアドバイスが載っていましたが、そのような語学力はありません。円安の声が聞こえ始めていたため、至急、再発注しました。解像度480x272はジャックボックス直行です。

XHコネクタ

JST製の極数3のXH基板用コネクタが、秋月でもDigi-Keyでも在庫ゼロになっていました。半導体不足の余波としては、極数3だけ欠品なのが不思議な感じがします。どこに大量需要があったのでしょうか・・・。

Backpackボードでは4個必要で、中1つは電源コネクタのため必須です。大手通販に互換品のセットがあったため助かりました。結果として、極数を確認して1個づつ発注するより楽でした。

XH connectors.

互換品の場合は成形型の公差による相性の問題が発生しそうですが、基板ポスト、ハウジング、コンタクトの全てが同じメーカ品で揃うため、相性の問題は発生しないと思われます。

レギュレータ

Scherer OMのBOM(部品構成表)では、12V電源から5Vに変換するレギュレータとしてLinear RegulatorのLM7805(出力1A)が指定されています。

入出力デバイスの消費電力は不確定です。Mike OMはこれをSwitching RegulatorのLC78_05-3.0(出力3A)に換装しています。Switching frequencyは150KHzです。リップル等のノイズは問題ないとの報告がありました。変換効率は95%弱あるためヒートシンクは必要なく、リード配置はLM7805と互換性があります。ネジによる密着固定の必要はなく、リードのはんだ付けだけで済みます。当局もこちらを採用し、Digi-Keyから入手しました。

5V power supply.

なお、5V電源はBackpackボードからTeensyに供給するため、TeensyのUSB電源パッドを切断する必要があります。TeensyのI/Oは3.3Vです。3.3V(250mA)のレギュレータはTeensyおよびAudio Adaptorに搭載されています。

タンタルコンデンサ

22uF成形タンタルコンデンサは高価です。京セラの米国子会社AVX製のコンデンサですが、国内の調達先を見つけることが出来ず、これもDigi-Keyから入手しました。「2022年4月以降を目途に日本、中国はじめアジアにおける営業組織も統合を予定」とのことですから、国内小売に潤沢に流通するのはもっと先になるかもしれません。

Scherer OMのBOMでは入出力の両方に22uFが配置されていましたが、LC78_05-3.0のデータシートの標準回路では入力側が安価な10uFになっていました。これ幸いと10uFに変更しました。パターン寸法が合わないため、リードの切れ端で継ぎ処理をしました。

組立の注意点

SMD部品

SMDのパスコンとTwin Peaks検出用ラインのインピーダンス抵抗は裏面に取り付けました。表面にも若干のSMDコンデンサダイオードを付ける必要があります。コネクタポストやピンソケットが林立するため、これらSMDは定石通りに先に付ける必要があります。

Teensy 4.1 ピンヘッダ剣山

Teensy 4.1は一瞥ではDIP(Dual Inline Package)配置のピンヘッダで接続するように見えます。しかし、Teensy 4.1は24x2のDIP配列のピンヘッダの他に以下のI/Oを接続するピンヘッダが必要になります。

  1.  USB Host (5x1 Pin Header)
  2.  Battery (5x1 Pin Header)
  3.  Ethernet (3x2 Pin Header)(2㎜ pitch)

Pin header sword mountain on the back side of Teensy 4.1.

これらの高密度に配置された孤島ピンヘッダは、本来はTeensy 4.1の表面に立ててフラットケーブル等で信号を引き出すことを想定しているようです。しかし、Backpackボードにはこれら孤島ピンヘッダに対してもスルーホールと配線パターンが準備されているため、なんとしても下にピンヘッダを降ろしてボードと接続する必要があります。

孤島ピンヘッダの中であい路になるのは、(3)Ethernetの3x2配列のピンヘッダです。これだけがフラットケーブル用の2.0mmピッチです。2.0㎜ピッチのヘッダ/レセプタクルの組み合わせは簡単には見つかりません。探し回って、唯一見つかったのがMETZ CONNECT社の下写真のヘッダ/レセプタクルです。

2mm pitch header and receptacle from METZ CONNECT.

しかし、2.5mmピッチのソケットとは高さが合いません。慎重に寸法を計算したところ、レセプタクルを2段重ねにすると、出っ張ることなく且つボードに届きそうな感じでした。ヘッダのピンの長さは3.9mm、対してレセプタクルのリードは細い上に長さは2.2mmでピン長さの56%しかありません。レセプタクル同士の嵌合は正しい使い方ではないため、接続の信頼性には懸念が残ります。

実物を入手してレセプタクルを2段重ねに嵌合したところ、挿入時に抵抗感があったため内部のコンタクトとの接合は取れたようです。テスタで導通チェックをしたところ、Teensyからボードのパターンまで導通を確認できました。

Audio Adaptor ピンヘッダ剣山

Audio Adaptorも14x2のDIP配列のピンヘッダの他に以下のI/Oを接続するピンヘッダが必要になります。

  1.  LINE IN(2x2 Pin Header)
  2.  LINE OUT(3x1 Pin Header)
  3.  Mic(2x1 Pin Header)

Pin header sword mountain on the back side of Audio Adaptor.

唯一、Headphone出力のみが基板上のステレオミニジャックに接続するようになっています。

LINE INとLINE OUTが同じ配列になっていないのは、誤挿入を避けるためでしょうか。5x2配列のピンヘッダの一本の頭をニッパで切ってAudio Adaptor付けました。ソケットの方はスルーホールの無い3本のコンタクトを抜いてBackpackボードに付けました。

 

以上で動作検証に向けた当座の組立は完了です。ディスプレイと合体しました。

The Backpack board, assembled and combined with the display.

点灯試験

点灯試験用ソフトウェア

点灯試験に用いたKeiths' SDRソフトウェアは2022年4月3日のMike OM版です。2022年4月24日に公開されたこのBackpackボードをMike OMは当時まだ利用していなかったと思います。最新版に更新すべきですが、コンパイルを通すまでに工数がかかることが予想されるため、取り急ぎコンパイル済みの古いバージョンで点灯試験を行いました。

コンパイラによるメモリの割付状況は以下の通りでした。

Memory Usage on Teensy 4.1:
    FLASH: code:160548, data:129616, headers:8840  
     free for files:7827460
    RAM1: variables:201408, code:132632, padding:31208  
     free for local variables:159040
    RAM2: variables:156576   
     free for malloc/new:367712

コードはPCからFLASH(8MB)に書き込まれ、実行時にRAM1に読み込まれます。RAM1(512KB)とRAM2(512KB)はチップ混載のメモリです。マルチコアではなくシングルコアにした代わりに、大容量のメモリを混載している点がIMXRT1060RMマイコンの特徴です。混載メモリの有効活用がポイントですが、今のところコンパイラの自動割り付けにお任せです。

超高速アクセスのRAM1がコードおよびローカル変数用で、RAM1を有効活用すればDSP演算が高速になるはずです。197KBがローカル変数に割り付けられ、まだ155KBの余裕があります。

RAM2はDMAアクセスに最適化されており、コーディックからのIQデータはRAM2に格納されると思われます。153KBが割り付けられ、359KBが未使用です。

点灯

Display lights up with no problem.

無事に点灯しました。まだディプレイに保護シールが付いたままですが、実物は写真よりも綺麗に発光しています。

最初はバックライトが点灯するのみでGUIが描画されず焦りましたが、何回か書き込みとRESETを繰り返すと無事にGUIも点灯し一息つきました。原因は不明ですが、規模の大きなSDRソフトのため、シリアルFLASH(W25Q64JV)へのSPIによるコード書き込み、あるいはその後のオンチップRAMへのコード転送に思ったよりも時間を要していたのかもしれません。

RFフロントエンドをまだ接続していないため、IQ信号コネクタは解放状態です。それにも係わらず、初期設定の28.074MHzの両側にピークが立っています。事前に信号処理連鎖を調査してきたため、この正体が何かは推測できます。

"Twin Peaks"状態検出用のテスト信号と思われます。矩形波であるためスペクトルが拡散していることも確認できます。テスト信号はAudio AdaptorのIQ信号ラインに重畳しているため、Audio Adaptorのコーディックが正常に動作していることも確認できました。

"Twin Peaks"状態検出テストおよび補正は一瞬にして終わり、テスト信号発振を終了して受信状態に遷移するはずですが、"Twin Peaks"状態検出テスト状態に留まったままなのはバグと思われます。そのバグのおかげで動作確認ができたわけですが・・・。Backpackボードに合わせて一部のコードを修正していますが、まだ不完全なのかもしれません。

Serial.print()文

無事に点灯したため、デバックに移行できます。Serial.print()文が重要なデバック手段になります。VisualTeensy導入時に、TeensyとPCの間の通信を担うTyCommanderを導入していました。

TyCommanderの"Serial"ボタンの"Serial"タブに、TeensyがSerial.print()文で出力したテキストが書き出されます。

In the "Serial" tab of the "Serial" button in the TyCommander, the text output by Teensy in the Serial.print() statement is written out.

以下、Mike OMが出力したテキストメッセージを確認します。

Initializing SDR_RA887x Program
FFT Size is 4096
**** Running I2C Scanner ****
Scanning...
I2C device found at address 0x0A  (SGTL5000)
I2C device found at address 0x38  (RA8875,FT6206)
done

最初にI2Cスキャナが走り、Teensyに接続されたI2Cデバイスを探索しています。コーディック(SGTL5000)、ディスプレイコントローラ(RA8875)、タッチコントローラ(FT6206)が見つかったとの報告が出力されています。I2Cエンコーダはまだ接続していないため、過不足なくI2Cデバイスが見つかっています。

Initializing RA8875 Display
RTC has set the system time
0:00:01 1 1 2019
Clock Update
Start of Spectrum Parameter Generator List.
This is a complete parameter record for the current window.
Cut and paste the data in the braces to modify the predefined records.
{798,0,0,0,798,398,14,8,157,179,179,408,400,110,111,289,289,0,153,799,256,50,20,2,330,1.0,0.9,1,40,-175,70}
End of Spectrum Parameter Generator List
Current Preset=0  Selected Preset=0  Current Waterfall Style=2  Current Color Temp=330

RA8875コントローラを搭載したDisplayの初期化をしています。Displayコードはまだ調査していないため詳細は不明です。スペクトルウオーターフォール関係のパラメータ設定が表示されているようです。

Initial Dial Frequency is     28.074.000MHz
Start W7PUA AutoI2S Error Correction
Using I/O pin for cross-correlation test signal.

Update  ------------ Outputs  ------------
Number  xNorm     -1        0         1   Shift Error State
7,  142.300888, -2.565808, 69.527359, 0.903492, 0,   0,    2
FM Initialization errors: 0
Initializing Notch/NR Feature = 32
Switching to Rx
 Reset Codec 

"Twin Peaks"状態検出テストの結果が表示されています。RF受信信号がテストの外乱にならないように、VFO周波数を28.074MHzに設定しています。国内のバンドプランではCWおよび狭帯域データのバンドに含まれます。

テスト結果の出力は以下の通りです。

  1. Number(nMeas):7 (測定7回)
  2. xNorm(xNorm):142.300888(相関関数絶対値の総和、理論値124)
  3. -1(xcVal[3]):-2.565808(シフト3のIQデータベクトル積和、理論値0)
  4.  0(xcVal[0]):69.527359(シフト0のIQデータベクトル積和、理論値62)
  5.  1(xcVal[1]): 0.903492(シフト1のIQデータベクトル積和、理論値0)
  6. Shift(neededShift):0(IQシフト補正不要)
  7. Error(TPerror):0(テスト信号エラー無し)
  8. State(TPstate):2(TP_RUN ← TP_MEASURE、補正実行モード)

"Twin Peaks"(IQシフト)は検出されず、終了しているようです。IQ相関係数の正規化前のIQデータベクトル積和はノイズによって理論値からずれますが、大きなずれは無いようです。

とすると点灯後の残照スペクトルは、IQコネクタを解放していることによりノイズが混入しているのかもしれません。信号レベルはS1~S2で大きくはありません。

最後に、受信状態に遷移してコーディックのリセット関数を終了した旨のメッセージを表示しています。

Help: Available Commands:
   h: Print this help
   C: Toggle printing of CPU and Memory usage
   T+10 digits: Time Update. Enter T and 10 digits for seconds since 1/1/1970
Loop T=2049  Spectrum T=106

Serialデバックのヘルプです。TyCommanderから送信入力できますが、入力するとTeensyのディスプレイ画面がフリーズします。

タッチ操作も効かないようです。Keiths' SDRソフトウェアMike OM版をこのBackpackボード上で開発した最新版にアップデートすることが次の課題です。

Teensy(16)Keiths' SDRのTx信号処理連鎖

Keiths' SDR(K7MDL局Mike OM版)の信号処理連鎖を学び中です。Rx信号処理連鎖の解読には一区切り付きました。Rx信号処理連鎖にもまだ不明確な点(サンプリング周波数とHilbertフィルタの帯域など)がありますが、Tx信号処理連鎖の解読に着手しました。

信号処理連鎖

ソースコードから読み取ったRx信号処理連鎖(青色の有向エッジ)とTx信号処理連鎖(赤色の有向エッジ)を下記に示します。前回までに詳説したRx信号処理連鎖は簡略化して示しています。前回調べたTwinPeakオブジェクトも省略しています。

Transmit signal processing chain (red edges).

赤色の有向エッジが今回調べたTx信号処理連鎖の経路です。黒色の有向エッジはRx/Tx共用の有向エッジです。

コーデック

ダイレクトコンバージョン方式のSDRでは、オーディオコーデック(ADC、DAC)が物理世界とのインターフェースになります。Keiths' SDRでは、NXP社のSGTL5000チップを搭載したPJRA社のAudio Adaptor Boardを採用しています。

最初に、RxとTxで切り変わるコーデックの入出力を整理しておきましょう。

Switching of audio codec input/output with switching between transmit and receive modes.

Rxモードでは、青字で示すように、ステレオLine入力からI/Q信号を入力して、Rx信号処理を適用し、ヘッドフォンに出力します。

Txモードでは、赤字で示すように、Mic入力からモノラル音声信号を入力して、Tx信号処理を適用し、ステレオLine出力からI/Q信号を出力します。

コーデックへの入力元およびコーデックからの出力先の切換えは、PTT信号をトリガーとしたRx/Txのモード切換え時に、codec1オブジェクトに入力/出力対象の指定メソッドを出すことで行います。

Rx信号処理連鎖の経路

Rx信号処理連鎖の調査で詳しくは言及しなかった2種類のスイッチオブジェクトが、Rx/Txモード切換え時に重要な役割を果たします。その観点から、Rx信号処理連鎖の経路を復習します。

Path of the Rx signal processing chain.

(1)Inputオブジェクト

Line入力のI/Q信号をコーデックがディジタルデータに変換し、InputオブジェクトにI2Sバス経由でDMA転送します。Inputオブジェクトは2つの出力ポート(0番、1番)を持ち、出力ポート0番からLチャネルのデータを受信Iデータとして出力し、出力ポート1番からRチャネルのデータを受信Qデータとして出力します。

(2)I_Switch/Q_Switchオブジェクト

Inputオブジェクトの出力であるI/Qデータを2つのスイッチオブジェクト(I_SwitchおよびQ_Switch)の入力ポート0番にそれぞれ入力します。I_SwitchおよびQ_Switchは、Mixerクラス(正式名はAudioMixer4_F32クラス)のオブジェクトです。Mixerクラスは本来、データストリームに対するゲイン係数を持つ加算器です。ゲイン係数を0/1で切換えることにより、何番の入力ポートのデータを出力するかを選択可能な入力ポート切換スイッチとして働きます。ここで使用しているMixerクラスは4つの入力ポート(0番~3番)を持ち、Rxモードではそれぞれ入力ポート0番の受信I/Qデータを選択して出力します。

(3)RxTx_InputSwitch_L/RxTx_InputSwitch_Rオブジェクト

I_Switch/Q_Switchオブジェクトの出力を後段の2つのスイッチオブジェクト(RxTx_InputSwitch_LおよびRxTx_InputSwitch_R)に入力します。RxTx_InputSwitch_LおよびRxTx_InputSwitch_Rは、Switchクラス(正式名はAudioSwitch4_OA_F32クラス)のオブジェクトです。Mixerクラスとは逆に、Switchクラスは入力データを何番の出力ポートから出力するかを選択可能な出力ポート切換スイッチとして働きます。ここで使用しているSwitchクラスは4つの出力ポート(0番~3番)を持ち、Rxモードではそれぞれ0番の出力ポートを選択して受信I/Qデータを出力します。

(4)Rx信号処理ブロック

RxTx_InputSwitch_L/RxTx_InputSwitch_Rオブジェクトの出力をRx信号処理ブロックに入力します。Rx信号処理ブロックの内容は前回までに調査し報告しました。Rx信号処理ブロックは、受信I/Qデータにディジタル信号処理を適用して復調した受信オーディオデータを出力します。

(5)OutputSwitch_I/OutputSwitch_Qオブジェクト

Rx信号処理ブロックの出力を2つのスイッチオブジェクト(OutputSwitch_IおよびOutputSwitch_Q)に入力します。OutputSwitch_IおよびOutputSwitch_Qは、再びMixerクラス(正式名はAudioMixer4_F32クラス)のオブジェクトです。ここで使用しているMixerクラスも4つの入力ポート(0番~3番)を持ち、Rxモードではそれぞれ0番の入力ポートの受信オーディオデータを出力します。

(6)Amp1_L/Amp1_Rオブジェクト

OutputSwitch_I/OutputSwitch_Qオブジェクトの出力をオーディオ増幅器オブジェクト(Amp1_LおよびAmp1_R)に入力します。Amp1_LおよびAmp1_Rは、AudioEffectGain _F32クラスのオブジェクトです。オーディオ増幅ゲインの操作を行い、受信オーディオデータを出力します。モノラル信号ですが、左右の音量は独立に調整可能です。

(7)Outputオブジェクト

Amp1_L/Amp1_Rオブジェクトの出力をOutputオブジェクトに入力します。Outputオブジェクトは2つの入力ポート(0番、1番)を持ち、入力ポート0番にLチャネルのデータを入力し、入力ポート1番にRチャネルのデータを入力します。受信オーディオデータをOutputオブジェクトからコーデックにI2Sバス経由でDMA転送し、コーデックがアナログデータに変換し、Headphoneに出力します。

Tx信号処理連鎖の経路

受信ではスイッチオブジェクトの0番のポートを選択して、Rx信号処理連鎖の経路を実現していました。送信ではスイッチオブジェクトの1番のポートを選択して、Tx信号処理連鎖の経路を実現します。

Path of the Tx signal processing chain.

(0)codec1オブジェクト

codec1オブジェクトによるADCの対象入力信号を受信と送信で交互に切り換えます。受信時は、QSD(直交検波器)からのI/Q信号が入力されるLine-INがADCの対象に選択されています。送信時は、音声信号が入力されるMicをADCの対象にするように、codec1オブジェクトに入力切換の指示を出します。

(1)Inputオブジェクト

Mic入力のモノラル音声信号をコーデックがディジタルデータに変換し、InputオブジェクトにI2Sバス経由でDMA転送します。Inputオブジェクトは2つの出力ポート(0番、1番)を持ちますが、モノラル信号のため両者は同じデータになります。Tx信号処理経路では、出力ポート0番を利用しています。

(2)TX_Sourceオブジェクト

TX_Sourceは、Mixerクラス(正式名はAudioMixer4_F32クラス)のオブジェクトであり、送信用入力ソースを切り換えるスイッチの役割を果たします。

TX_Sourceは4つの入力ポートを持ち、Inputオブジェクトからの音声データ出力は入力ポート0番にプログラム上で結線されています。音声データ以外に、USB_Inオブジェクトからのデータが1番に、TxTestTone_Aオブジェクトからのトーン信号データが2番に、TxTestTone_Bオブジェクトからのトーン信号データが3番に、それぞれプログラム上で結線されています。

2つのトーンジェネレータは、2トーンテストのために準備されているものと思われます。2つのトーンジェネレータでクラスが異なり、AudioSynthSineCosine_F32とAudioSynthWaveformSine_F32に分かれますが、使い分けている理由は不明です。最初に存在した後者に対して、スペクトル純度を上げるために前者を作成し、その成果に基づき後者も更新している経緯が読み取れます。集合知で発展してきたソースコードの歴史的経緯の痕跡として、2つが残っているのかもしれません。

1番ポートに入力されるUSBデータはFT8等のデータ通信用ですが、CWのトーン信号の入力ソースとしても計画されているようです。CWの送信系は、クリック防止のためのエンベロープ制御も含めて、まだ完成を見ていないようです。QSE(直交変調器)とは別系統でCW送信系を準備するとなるとRFフロントエンドの改造が発生してしまうため、CWのトーン信号をTX_Sourceに入力してVFOをその分オフセットさせる変調CW方式に落ち着きそうです。FT8のGaussian filterに例があるように、CWのエンベロープ制御もソフトウェアによって処理され得ると思います。

(3)bpf1オブジェクト

音声信号に対するBPFです。このオブジェクトだけ命名規則(小文字のみ使用)が他と異なるため、実験的に挿入されている可能性があります。

BPFの機能は後段のHilbertフィルタと重複しますが、Rx信号処理連鎖と同様に、位相シフトとBPFの機能を分割したのではないかと思われます。機能分割しておけば、将来イコライザに進化させることも可能と思われます。

bpf1は、AudioFilterFIR_F32クラスのオブジェクトであることから、FIRフィルタであることが分かります。fir1係数配列を引数として初期化をしています。fir1係数配列の定義ファイルに下記のフィルタ仕様に関するコメントがありました。

FIR filter designed with http://t-filter.appspot.com
sampling frequency: 48000 Hz

// 0 Hz - 400 Hz   attenuation = -91.3 dB
// 900 Hz - 3200 Hz  ripple = 3.5 dB
// 4000 Hz - 22050 Hz  attenuation = -91.3 dB

サンプリング周波数が98kHzなのか48kHzなのか判然としていませんでしたが、コメントから推察するとbpf1は48kHzで設計されています。やはり、ソースコード上のサンプリング周波数98kHzはコーディック1チャンネル分の仕様であって、2チャンネル分では48kHzになるのではないかと推定されます。

bpf1のフィルタ特性を係数から調べた結果を下記に示します。400Hz~4,000HzのBPFになっていますが、attenuation = -91.3 dB を達成しているバンド幅はもう少しブロードになります。後段のHilbertフィルタのBPF特性よりも、DCを含めた低周波帯域と高周波帯域の減衰に優れているようですが、それを狙って追加したのかどうかは不明です。

Bandpass characteristics of the FIR filter examined from the coefficients of bpf1.

(4)Hilbertオブジェクト

Rx信号処理連鎖と同様に、±45度の位相シフトを行う二つのHilbertフィルタが準備されています。2.8kHzの通過域を名前に持つHilbert_Plus45_28K係数配列およびHilbert_Minus45_28K係数配列を引数として、それぞれのオブジェクトの初期化をしています。Rx信号処理連鎖で調べたフィルタ特性を下記に再録します。

Hilbert FIR filter with a cutoff frequency of 2.8 kHz.

以上の(2)から(4)までのブロックが、Tx専用の信号処理連鎖になります。

(5)(6)(7)スイッチオブジェクト

Hilbertオブジェクトの出力は、(5)I_SwitchおよびQ_Switchオブジェクトの入力ポート1番にプログラム上で結線されています。送信時には入力ポートを0番から1番に切り換えます。

同時に、(6)RxTx_InputSwitch_L/RxTx_InputSwitch_Rオブジェクトの出力を0番から1番に切り換え、Rx信号処理ブロックをバイパスして、(7)OutputSwitch_IおよびOutputSwitch_Qオブジェクトの入力ポート1番に直結します。

(8)(9)QSEへの出力オブジェクト

(7)OutputSwitch_IおよびOutputSwitch_Qオブジェクトの出力は、Rx信号処理連鎖と同じく、オーディオ増幅器オブジェクト(8)Amp1_LおよびAmp1_Rにプログラム上で結線されています。IQバランス等の用途でゲインは調整可能ですが、初期値1.0のまま使われているようです。

送信IQデータを(8)OutputオブジェクトからコーデックにI2Sバス経由でDMA転送します。送信時には、コーデックの出力先をHeadphoneからLine-OUTに切り換えておきます。コーデックが送信IQデータをアナログデータに変換し、Line-OUTからQSEに出力します。

以上が主にSSBを対象にしたTx信号処理連鎖になります。Rx信号処理連鎖よりも簡易な連鎖になっています。FT8等のデータ通信や、PCからKeyingする変調CWを深掘りするためには、USB_In/Outオブジェクトをさらに調べる必要がありそうです。

AFP-FSK Transceiver(16)20mバンドモジュールの測定

QRPGuys AFP-FSK (Audio Frequency Processed - Frequency Shift Keying) Digital Transceiver III に標準で付いてくる40m/30m/20mバンドモジュールの中で最後に残った20mバンド(14MHz帯)モジュールの測定を行いました。

送信電力の測定

バンドモジュールを20m用に換装すると、バンドID抵抗の分圧値をADCで読み取り、周波数を自動的に14.074MHzに設定しました。バンドID抵抗の公差に問題は無いようです。

測定方法

送信電力はUSBオシロスコープ(AnalogDiscovery2)で測定しました。DC電源は13.8Vです。

Measurement system of transmit power by USB oscilloscope (AnalogDiscovery2).

測定結果

Measurement result of dummy load voltage by USB oscilloscope (AnalogDiscovery2).

ダミーロード電圧のAC RMS(実効値)から送信電力を計算すると6.3W、ピーク電圧から計算すると6.1Wになりました。40m/30mとほぼ同じ値です。E級増幅による送信電力にはハイバンド化の影響は出ていないようです。

スプリアス領域における不要発射の強度の測定

測定方法

tinySAを用いた「スプリアス領域における不要発射の強度」の測定系を下記に示します。

Measurement system for the strength of unwanted emissions in the spurious region.

送信出力6.3(W)は38.0(dBm)となるため、手持ちのMax. 41dBのステップアッチネータで39dB減衰して-1.0(dBm)をtinySAに入力しました。

tinySAはPC上のtinySA-Appから制御しました。周波数掃引範囲は10~75MHzとしました。分解能帯域幅RBWは自動設定とし、周波数掃引点数を変えて測定を繰り返しました。

測定結果

Measurement result of unwanted emission intensity in the spurious region by 500 frequency sweeps.

Measurement result of unwanted emission intensity in the spurious region by 1,000 frequency sweeps.

Measurement result of unwanted emission intensity in the spurious region by 3,000 frequency sweeps.

Measurement result of unwanted emission intensity in the spurious region by 10,000 frequency sweeps.

Summary of unwanted emission intensity measurements in the spurious region.

最も強度が高い不要発射は掃引3,000点時の第三高調波-51.3(dBc)でしたが、スプリアス規格を満たします。

第二高調波は平均-57.0(dBc)となり、無調整のウェーブトラップによって良く抑えられています。

スプリアス規格を満たしましたが、バンド周波数が上がると余裕が小さくなることが分かりました。次の17mは、第三高調波が境界条件上に比掛かるか、規格をオーバしそうな予感がします。経験上、第三高調波が規格を満たさない場合は、簡易なウェーブトラップの調整ではなく、LPFの段数を増やす改造が必要になります。

帯域外領域におけるスプリアス発射の強度の測定

測定方法

USBドングルSDRのSDRplay(RSP1A)を用いて「帯域外領域におけるスプリアス発射の強度」を測定しました。測定系統図と測定の様子を下記に示します。

Measurement system diagram of spurious emission intensity in the out-of-band region.

送信出力6.3(W)の38.0(dBm)に対して、20dBカプラで分岐し、手持ちのMax. 41dBのステップアッチネータと20dB固定アッチネータを通して減衰し、-43.0(dBm)の信号をSDRplayに入力しました。

測定結果

Measurement of spurious emission intensity in the out-of-band region.

SDRplayへの入力信号の測定強度は-44.4(dBm)でした。公称値による机上の概算予想-43.0(dBm)との乖離は1.4(dBm)でした。終段の温度上昇によって出力が減少する影響もあると思います。受信強度としては、S9+30dB弱の表示です。

帯域外±10kHzの領域のスプリアス発射の強度は-92.6(dBm)以下でした。帯域外領域におけるスプリアス発射の強度は基本波より48.2(dB)低い値となり、許容値に収まります。絶対値は1.2(mW)となり、こちらも許容値に収まります。

SDRplayとPCソフトウェアSDRunoの組み合わせによる20mバンドのRBWは最小5.93Hzになります。周波数軸を最大限拡大した結果を下記に示します。スペクトル中心のオフセットはRBW以下でした。

Expansion of the frequency axis around the fundamental frequency in the spectrum measurement result.

以上により、QRPGuys AFP-FSK Digital Transceiver III の3バンド(40m/30m/20m)化の準備が整いました。20mバンドモジュールも、LPFのトロイダルコイルについて巻き方等の調整は必要ありませんでした。ただし、40m/30mバンドよりも余裕が少なくなっているため、ハイバンドでどうなるか予断を許しません。

AFP-FSK Transceiver(15)30mバンドモジュールの測定

QRPGuys AFP-FSK (Audio Frequency Processed - Frequency Shift Keying) Digital Transceiver III に標準で付いてくる30mバンド(10MHz帯)モジュールの測定を行いました。

送信電力の測定

バンドモジュールを30m用に換装すると、バンドID抵抗の分圧値をADCで読み取り、周波数を自動的に10.136MHzに設定しました。

送信電力はUSBオシロスコープ(AnalogDiscovery2)で測定しました。DC電源は13.8Vです。

Measurement system of transmit power by USB oscilloscope (AnalogDiscovery2).

Measurement result of dummy load voltage by USB oscilloscope (AnalogDiscovery2).

ダミーロード電圧のAC RMS(実効値)から送信電力を計算すると6.0W、ピーク電圧から計算すると6.2Wになりました。40mとほぼ同じ値です。E級増幅QRPトランシーバに採用例の多い3並列FET(BS170)の終段回路として優秀な部類に入ると思います。

実効値は多点の数値積分に基づいて計測していると思いますが、ピーク電圧は最大値と最小値の2点から計測していると思います。大きな差はありませんが、実効値の方が信頼性が高いと思われます。

E級増幅スイッチングタイミングの測定

高出力の秘密はE級増幅のスイッチングタイミングにあると思われるため、その測定を試みました。下図の左にゲートソース間電圧Vgsと出力電圧V(ant)を示し、右にVgsとドレインソース間電圧Vdsを示します。

Measurement results of switching timing of FETs for class-E amplification.

Vgsは同じテストピンから同じ配線で測定しているにもかかわらず、リップルが大きく異なります。狭隘部から測定のための配線を引き回しているため、正確な測定ができていません。

ゲートのON/OFFのタイミングは想像で記入しました。測定配線に誘導されているリップルが大きいため心眼で判定するしかありませんが、Vdsがゼロのタイミングでスイッチングできているように思います。

スプリアス領域における不要発射の強度の測定

測定方法

tinySAを用いた「スプリアス領域における不要発射の強度」の測定系を下記に示します。

Measurement system for the strength of unwanted emissions in the spurious region.

送信出力6(W)は37.8(dBm)となるため、手持ちのMax. 41dBのステップアッチネータで減衰すると-3.2(dBm)となり、tinySAの安全入力範囲に収まります。

tinySAはPC上のtinySA-Appから制御しました。周波数掃引範囲は5~55MHzとしました。分解能帯域幅RBWは自動設定とし、周波数掃引点数を変えて測定を繰り返しました。

周波数掃引500点

Measurement result of unwanted emission intensity in the spurious region by 500 frequency sweeps.

周波数掃引1,000点

Measurement result of unwanted emission intensity in the spurious region by 1,000 frequency sweeps.

周波数掃引3,000点

Measurement result of unwanted emission intensity in the spurious region by 3,000 frequency sweeps.

周波数掃引10,000点

Measurement result of unwanted emission intensity in the spurious region by 10,000 frequency sweeps.

まとめ

基本波の強度は平均2.05(dBm)となり、事前想定からの差異は1.15(dBm)に収まりました。ステップアッチネータキットの抵抗値の公差から考えて、誤差の範囲と思います。

tinySAの周波数掃引点数を増やすと、自動設定のRBW(kHz)が小さくなることによって周波数解像度が上がり、ノイズフロアが下がります。強度の測定結果に系統的な変動(掃引点数に比例して強度が下がるなど)は見られないため、平均を取ってまとめても良いかと思われます。

「スプリアス領域における不要発射の強度」の測定結果を下表にまとめます。

Summary of unwanted emission intensity measurements in the spurious region.

最も強度が高い不要発射は掃引10,000点時の第三高調波-54.3(dBc)でしたが、スプリアス規格を満たします。経験上、第三高調波が規格を満たさない場合は、簡易なウェーブトラップの調整ではなく、LPFの段数を増やす改造が必要になります。

第二高調波は平均-56.2(dBc)となり、無調整のウェーブトラップによって良く抑えられています。

帯域外領域におけるスプリアス発射の強度の測定

測定方法

USBドングルSDRのSDRplay(RSP1A)を用いて「帯域外領域におけるスプリアス発射の強度」を測定しました。測定系統図と測定の様子を下記に示します。

Measurement system diagram of spurious emission intensity in the out-of-band region.

送信出力6(W)の37.8(dBm)に対して、20dBカプラで分岐し、手持ちのMax. 41dBのステップアッチネータと20dB固定アッチネータを通して減衰し、-43.2(dBm)の信号をSDRplayに入力しました。

測定結果

Measurement of spurious emission intensity in the out-of-band region.

SDRplayへの入力信号の測定強度は-44(dBm)でした。公称値による机上の概算予想-43.2(dBm)との乖離は僅かに0.8(dBm)でした。受信強度としては、S9+30dB弱の表示です。もっと減衰させた方が良いかもしれませんが、手持ちのアッチネータは全て投入してしまいました。

帯域外±10kHzの領域のスプリアス発射の強度は-92(dBm)以下でした。帯域外領域におけるスプリアス発射の強度は基本波より48(dB)低い値となり、許容値に収まります。絶対値は1.2(mW)となり、こちらも許容値に収まります。

SDRplayとPCソフトウェアSDRunoの組み合わせによる30mバンドのRBWは最小0.95Hzになります。周波数軸を最大限拡大した結果を下記に示します。

Expansion of the frequency axis around the fundamental frequency in the spectrum measurement result.

綺麗なスペクトルになっていると思います。スペクトルの中心は約6Hzオフセットしていました。0.59ppm程度の誤差です。TCXOでも±2ppm程度の変動はあるため、許容範囲です。

以上により、QRPGuys AFP-FSK Digital Transceiver III の2バンド(40m/30m)化の準備が整いました。30mバンドモジュールも、LPFのトロイダルコイルについて巻き方等の調整は必要ありませんでした。ただし、40mバンドよりも余裕が少なくなっているため、ハイバンドでどうなるか予断を許しません。

AFP-FSK Transceiver(14)マルチバンド化の準備

日乗

KCJコンテストの結果速報が届きました。KCJコンテストは、提出ログを照合し一致したQSOのみ得点を認める厳格な規約になっています。

当局は、コンテストの終盤にCQを出されている局を競合局のいないタイミングで呼ぶスタイルのため、QSO数は僅かです。その中の1局には再送を繰り返して辛うじて取って頂いたため、正確にログが一致するかどうか心配していました。当局のコールサインでは「E」が鬼門と思います。ノイズに埋もれてしまう場合は、スペースから逆算して「E」を感じ取って頂く必要があるかもしれません。

心配は杞憂に終わり、コールサイン、RST、マルチの互いのミスコピーは皆無でした。厳格な規約も振り返りには好適です。「相手のログが提出されていない」による1ポイント減点で済みました。ログ未提出だとコールサインが相手方にその旨伝達されることが分かりました。気をつけねば・・・。

プロローグ

しばらく工作から遠ざかってSDRソフトウェアの勉強をしてきましたが、猛暑も収まり換気のために窓を解放して工作を行うのに適した季節になって来ました。そこで、QRPGuys AFP-FSK (Audio Frequency Processed - Frequency Shift Keying) Digital Transceiver III のマルチバンド化に取り組むことにしました。

QRPGuys AFP-FSK Digital Transceiver III 

AFP-FSK Transceiver はバンドID抵抗を備えたバンドモジュール(送信LPFと受信HPF)を差し換えることで、HF帯(160~10m)のバンドQSYが可能です。標準で40m/30m/20mのバンドモジュールのPCBと部品が付属します。他のバンドモジュールの設計データも公開されているため、部品を集めれば製作可能です。

Band Module Specifications

当局の環境ではアンテナの実現が困難な160m/80mバンドは諦めます。60mは国内では許可されていません。標準添付の残りの30m/20mのバンドモジュールに加えて、17m/15m/12m/10mのバンドモジュールを製作し、合わせて7バンド化を試みることにしました。

部品集め

適切なユニバーサル基板が有れば、ロジスティックスが心配なUSPS経由でQRPGuysから部品を取り寄せなくても済みます。aitendoで塩梅の良い80×20穴のユニバーサル基板(UPCB80X20D)を見つけました。秋月でも同様の仕様の安価な基板がありましたが、コスト削減のためか4隅のRが付いていない仕様になっていました。バンドQSY時に素手で換装する基板になるため、今回はaitendoの基板にしました。

Universal PCB (UPCB80X20D) with 80 x 20 holes.

コンデンサは、LPFのウェーブトラップ調整用に、250V C0G の(2012サイズ)チップ積層セラミックコンデンサの系列をストックしているため、そこから適宜使用することにします。

最も入手が困難だった部品は、受信HPF用の固定インダクタ(1.2uHと680nH)です。近接放送局が無ければ、受信HPFは省略しても良いかとも思いましたが、他の部品と抱き合わせでDigi-keyに発注しました。

Fixed inductors for HPF of received signals that may not be distributed domestically.

配置設計

フリーソフトウェアとして公開されているPasS(Parts Arrange Support System)という名称のユニバーサルプリント基板エディタを使って、追加バンドモジュールの配置設計を検討しました。

PasSは、部品のビットマップイメージの端子ドットの色で配線の結合を判定していると思われるユニークな基板エディタです。トロイダルコイルのイメージが無かったため、似た寸法の電解コンデンサのイメージを流用しました。

Design of band module placement on a universal board.

配線の自由度はコネクタ端子に拘束されます。どうしてもGND配線と交差する信号配線(赤色)が1ヵ所生じるため、裏面配線(青色)だけでは収まりませんでした。

配置設計の過程で、QRPGuysオリジナルのバンドモジュールの配置設計に対して気付きがありました。同じように巻いた2つのトロイダルコイルのINとOUTの割り振りを変えていることです。つまり、IN1⇒OUT1⇒OUT2⇒IN2というパターン配線になっています。これによって磁束の方向が反転し、互いに漏れ磁束を打ち消し合うようになります。追加バンドモジュールの配置設計でも踏襲することにしました。回路図には表れないノウハウです。本来は設計思想は漏れなく図面指示すべきなのですが・・・。

LPFの事前シミュレーション

第二高調波がスプリアス規格を満たすようにするためには、ウェーブトラップをLPFに付加する方法が有効であることを経験しています。QRPGuys設計のLPFにはウェーブトラップが初めから付いています。

共振を利用するウェーブトラップでは、手持ち系列のコンデンサ単品で組んだだけでは、スプリアス規格を達成できる保証がありません。そこで、事前にシミュレーションによる容量感度の検討を行いました。ウェーブトラップのC21はチップコンデンサ2個並列まで許容する方針としました。

17m(18MHz)

LTspiceによる17mバンドLPFのAC解析結果を示します。ウェーブトラップのコンデンサC21は、22pF/33pF/39pFとして感度を調べまし。設計指示値は22pFです。

トロイダルコイルのインピーダンスは実測すべきですが、手持ちのLCRメータでは低インピーダンス領域になり、精度の高い測定は出来ませんでした。toroids.infoの計算値を用いています。

AC analysis result of 7m-band LPF by LTspice.

18MHzの第二高調波36MHzで共振するC21は、設計指示値22pFより大きな33pFであることが分かりました。

初段のコンデンサC24は「No C24」(実装不要)との指示がありました。これではLPFがチェビシェフ型にならない上に、E級増幅にも影響を及ぼしそうです。

LPFを搭載したバンドモジュールはコネクタ経由でメイン基板と結合するため、浮遊容量が隠れている可能性があります。それでも、1pF以下のオーダではないかと思われます。逆に、E級増幅の条件を最適化するために、LPFの仕様を二の次にしているのかもしれません。

15m(21MHz)

LTspiceによる15mバンドLPFのAC解析結果を示します。ウェーブトラップのコンデンサC21は、22pF/24pF/33pFとして感度を調べまし。設計指示値は22pFです。

AC analysis result of 15m-band LPF by LTspice.

21MHzの第二高調波42MHz付近で共振するC21は、設計指示値22pFより大きな24pF(12pF+12pF)であることが分かりました。

手持ちのコンデンサでは、22pFの次の系列は33pFになるため、12pFを2個組み合わせる必要があります。

12m(24MHz)

LTspiceによる12mバンドLPFのAC解析結果を示します。ウェーブトラップのコンデンサC21は、15pF/18pF/22pFとして感度を調べまし。設計指示値は15pFです。

AC analysis result of 12m-band LPF by LTspice.

24MHzの第二高調波48MHz付近で共振するC21は、設計指示値15pFより大きな18pFであることが分かりました。

10m(28MHz)

LTspiceによる10mバンドLPFのAC解析結果を示します。ウェーブトラップのコンデンサC21は、15pF/18pF/22pFとして感度を調べまし。設計指示値は15pFです。

AC analysis result of 10m-band LPF by LTspice.

28MHzの第二高調波56MHz付近で共振するC21は、設計指示値15pFより大きな18pFであることが分かりました。

事前検討のまとめ

総じて、ウェーブトラップのコンデンサC21を設計指示値よりも大きな容量にした方が良いという結果になりました。

わざわざ適正ポイントを外す設計をするとは思えないため、予想外に大容量の浮遊容量への対応等、設計の秘密が何か隠されているような気がします。

設計指示値通りに製作して、性能が未達となった時に、シミュレーションが示す適正値に変更する方針の方が良いかもしれません。

欠品 #26AWG UEW

コイルを巻き始めたのですが、QRPGuys支給のポリウレタン銅線(UEW線)はさすがに途中で費えました。手持ちのUEW線はΦ0.29mmとΦ0.5mmですが、指定は#26AWGでした。American Wire GaugeをUEW線の仕様で使う例を国内ではあまり見たことがありません。小分け売りのUEW線のパッケージにもAWGの表記はありません。

調べてみると、#26AWGはΦ0.4mm、安全電流0.32Aでした。5Wだと実効値で0.32A程度は流れそうなのでΦ0.29mmは危険と判断。Φ0.5mmだと巻いた時の曲げRが大きくなり、トロイダルコアとの密着が悪くなりそうです。設計指定通り#26AWG=Φ0.4mmを調達することにしました。しばし中断です。

Teensy(15)Keiths' SDRの"Twin Peaks"問題解決方法の調査

"Twin Peaks"問題とは

概要

SGTL5000コーディック(ADコンバータ、DAコンバータ)を搭載した、PJRC社のTeensy用オーディオアダプタには、起動時にIQ信号の片方の先頭データが欠落することがあるという問題が指摘されています。音声や音楽のステレオオーディオ信号を扱う場合は問題にならないようですが、IQ信号では大問題になります。これによって、それ以後のIQ信号相互の位相関係がシフトするため、IQ信号演算によるイメージ抑圧が正常に働かなくなります。その結果、搬送波の両側に信号ピークが立つ状況になるため、"Twin Peaks"と称されているようです。

この問題が存在することを知らないと、ある日突然、昨日まで順調に動いていたトランシーバの復調が出来なくなり、無暗にPCの再起動や再コンパイルを繰り返す等の都市伝説的対処に走ることになります。

幸いなことに、コミュニティにて原因の特定とSDRソフトによる解決策の造り込みが図られているため、調査した結果をここにまとめます。

経緯

  1. 2017/02/24
    Convolution SDRで著名なDD4WH局Frank OMが、PJRC社のフォーラムに「Reset audio board codec SGTL5000 in realtime processing」という名称のスレッドを立て、コーディックの問題提起をされたのが最初かと思います。
    Frank OMはこの時点で既に、IQ信号が欠落することが"Twin Peaks"の原因だと気付いておられます。mcHFトランシーバのコーディックWM8731でも同じ問題があり、コーディックのリセットで解決したことも記されています。コーディックSGTL5000でも同じ手段が取れるかどうかに問題が絞られています。
    人が気付いて対処するか(手動)、Teensyが気付いて対処するか(自動)が課題になります。
  2. 2018/04/16
    W7PUA局 Bob Larkin OMが議論に参加。様々なサンプリング周波数の設定で"Twin Peaks"問題が発生することを報告。
  3. 2018/05/22
    TeensyからSGTL5000に出力するClockのジッターが根本原因ではないかとの仮説を立て、これを減らすことを検討してスレッドの更新は止まっています。
    Clockのジッターが"Twin Peaks"の根本原因ではなかったようです。根本原因はTeensy側ではなくSGTL5000側に内包されているとして、対処療法で解決することが必要になりました。
  4. 2022/03/09
    W7PUA局 Bob Larkin OMからPJRC社のフォーラムの「 Floating-Point Audio Library Extension」スレッドに投稿があり、"Twin Peaks"問題を解決するAudioAlignLR_F32クラスをOpenAudio_ArduinoLibraryに追加したとのアナウンスがありました。提案された解決方法は後述します。
  5. 2022/03/10
    W7PUA局 Bob Larkin OMからkeithsdr@groups.ioに「Codec mis-aligned L-R timing」と題する投稿があり、"Twin Peaks"問題を解決するAudioAlignLR_F32クラスをOpenAudio_ArduinoLibraryに追加したとの同じアナウンスがこちらにもありました。
  6. 2022/04/09
    N0CTL局 John Scherer OMからkeithsdr@groups.ioの「PCB for Teensy + Teensy audio shield + RA8875」スレッドに投稿があり、Scherer OM設計のPCBに"Twin Peaks"の能動的自動検出のための回路パターンを搭載した旨の報告がありました。
  7. 2022/05/19
    K7MDL局Mike OMからkeithsdr@groups.ioの「Codec mis-aligned L-R timing」スレッドに投稿があり、AudioAlignLR_F32クラスを用いた"Twin Peaks"問題解決機能をKeiths' SDR(K7MDL局Mike OM版)ソフトウェアに標準搭載した旨の報告がありました。

以上で、ハードウェアとソフトウェア(ライブラリとアプリ)の両面で"Twin Peaks"問題は解決されました。こうして経緯をまとめると、集合知による課題解決絵巻のようです。

"Twin Peaks"問題の解決方法

問題

コーディックSGTL5000からのDMA転送データには、起動時にIQ信号の片方の先頭データが欠落することがあるという問題が存在します。Hilbertオブジェクトの調査の際にイメージ抑圧のシミュレーションに用いたPythonプログラムを流用して、具体的に何が起こるか見てみましょう。

I/Q信号の欠落シフトが無い健全な場合のイメージ抑圧結果を再録します。目的のIn-phase信号はHilbertフィルタ後段のSummerを通過し、Image信号はSummerで相殺されることが分かります。

Image suppression results for a healthy case with no shift due to missing I or Q signals.

I信号の欠落シフトが有る不健全な場合のイメージ抑圧結果を示します。目的のIn-phase信号はHilbertフィルタ後段のSummerを歪を伴って通過しています。ただし、その歪は目視で確認できるほど大きくはありません。

一方、Image信号はSummerで完全には相殺され得ないことが分かります。これにより、In-phase側とImage側の両方にピークが立つことになります。これがTwin Peaksです。

Image suppression results for the unhealthy case where there is a shift due to the missing I signal.

Q信号の欠落シフトが有る不健全な場合のイメージ抑圧結果を示します。Imageの位相が異なるだけで、同様にTwin Peaksが発生することが分かります。

Image suppression results for the unhealthy case where there is a shift due to the missing Q signal.

僅かにデータ1個分シフトしただけで、このような大きな影響が出ることが確認できました。

解決方法の原理

"Twin Peaks"問題が顕在化するタイミングは不定です。よって、SDR起動時に能動的に検出する方法が探られました。

IQサンプリングデータの欠落の有無を検出するために、起動時にコーディックの両L/Rチャンネルに同じテストデータを能動的に注入して比較する方法が採用されました。Teensy 4.x自体はDACを搭載していないため、サイン波を注入することは断念し、有り余るディジタル出力ピンの1つ(22番)から矩形波を注入しています。テスト時にRF信号を切断できると良いのですが、リレー回路等が必要になり複雑化するため、RF信号にテスト信号を重畳する方法が取られています。したがって、起動時に静かなバンドで"Twin Peaks"検出を行う必要があります。

サンプリング周波数の1/4の周波数の矩形波をコーディックに注入しています。下記に示すように、1周期に4点のサンプリングを行うことになります。コーディックからのデータ転送ブロック長は128ワードのため、32個の矩形波をサンプリングして判定します。

Normal conversion data of SGTL5000 for test square wave from Teensy's digital output pin 22.

Lチャンネルに対してRチャンネルのサンプリングシフト3までの相関関数を計算して、データ欠損によるシフトの有無を判定します。サンプリングシフトによってRチャンネルの最後の矩形波は欠損するため、相関関数の計算に使用するデータブロック長は124ワードとしています。31個の矩形波を使用することでノイズへの耐性を高めていることになります。

能動測定によって、LチャンネルもしくはRチャンネルのどちらかに欠落シフトがあることが検出された場合は、Rx信号処理連鎖に送出するデータブロックに整列補正シフトを施す対策を実施しています。コーディックのリセットは行っていないようです。SGTL5000コーディックがリセット命令を備えていないのかもしれません。

以下、サンプリングシフトの能動的測定方法の詳細を場合分けして記します。

Case 1:欠落シフトが無い場合

Case 1:  Normal L-channel data without missing and normal R-channel data without missing.

Lチャンネル(I信号)とRチャンネル(Q信号)の両方に欠落シフトが無い場合は、Rチャンネルのシフトが0の時の相互相関(正規化していないので相互相関係数ではなくベクトル乗算)xc[0]が最大の62になり、シフトが2の時のxc[2]が最小の-62になります。その他のxc[1]とxc[3]は0になります。ノイズ耐性を高めるために差分を取って正規化すると、xc[0]-xc[2]が1となり、他は0です。しきい値0.7と比較して、欠落シフト無し(In phase)と判定しています。

Case 2:Lチャンネルが欠落シフトしている場合

Case 2: Shifted L-channel data with one missing and normal R-channel data without missing.

Lチャンネル(I信号)が欠落シフトしている場合は、Rチャンネルのシフトが1の時の相互相関xc[1]が最大の62になり、シフトが3の時のxc[3]が最小の-62になります。差分xc[1]-xc[3]の正規化値が最大の1となり、Lチャンネル(I信号)の欠落シフト有り(Shift I)と判定しています。

Case 3:2つ分欠落シフトしている場合

Case 3: Shifted L-channel data with two missing and normal R-channel data without missing.

Lチャンネル(I信号)が2つ分欠落シフトしている場合は、Rチャンネルのシフトが2の時の相互相関xc[2]が最大の62になり、シフトが0の時のxc[0]が最小の-62になります。差分xc[2]-xc[0]の正規化値が最大の1となりますが、DNApplyと判定してエラーを返しています。DNApplyは「Do not apply」ということでしょうか。この場合は、サンプリングシフトの再測定を行うようです。

Case 4:Rチャンネルが欠落シフトしている場合

Case 4: Normal L-channel data without missing and shifted R-channel data with one missing.

Rチャンネル(Q信号)が欠落シフトしている場合は、Rチャンネルのシフトが3の時の相互相関xc[3]が最大の62になり、シフトが1の時のxc[1]が最小の-62になります。差分xc[3]-xc[1]の正規化値が最大の1となり、Rチャンネル(Q信号)の欠落シフト有り(Shift Q)と判定しています。

ハードウェアの要件

Teensyのdigital output pin 22から矩形波を出力して、コーディックSGTL5000のLINE INの2つのチャンネル(L/R)に同時に入力する配線が必要になります。インピーダンス整合のために、当初は100kΩ抵抗を挟んでいましたが、10kΩ抵抗が最適であることがMike OMによって見出されています。

Hardware wiring for active detection of "Twin Peaks".

N0CTL局 John Scherer OMの設計による「Teensy 4.1 Ra8875 Backpack with Audio Shield」(REV.3)ボードには、"Twin Peaks"の能動的測定のための配線パターンが準備されています。

信号の名称は「I2S_COR」となっていますが、I2S信号ではないことに注意する必要があります。I2S通信プロトコルに乗るIQ信号(L/R信号)の相関を能動的に調べるためのディジタル出力信号という意味からの名称と思います。

公開されているBackpack PCBのガーバーファイルから、裏面のパターンを可視化して下記に示します。黄色の文字は当局の注記です。"Twin Peaks"の能動的測定のための配線パターンが確認できます。

Backside wiring of the Backpack PCB.
(You can see the wiring from the Tennsy 4.1 digital output to the audio adapter's LINE L/R.)

組立中のBackpack PCBの裏面写真を下記に示します。透視で表面から見たガーバーファイル可視化イメージとは鏡像関係にあることにご注意ください。

Photo of the backside of the Backpack PCB during assembly.

信号配線は表面にあり、本来、裏面にはバイパスコンデンサとプルアップ/ダウン抵抗が配置されているだけだったようですが、そこに重要な"Twin Peaks"能動的検出パターンが追加配置されたようです。

ソフトウェアへの実装

"Twin Peaks"の能動的測定のためのハードウェアの仕掛けに合わせて、ソフトウェアの準備も必要になります。Keiths' SDR(K7MDL局Mike OM版)における実装を見ていきたいと思います。

W7PUA局 Bob Larkin OMが開発したAudioAlignLR_F32クラスのTwinPeakオブジェクトを、K7MDL局Mike OMがRx信号処理連鎖の先頭に挿入しました。このオブジェクトによって、先頭データの欠落シフトの能動的測定と、必要に応じて後段のRx信号処理連鎖に送出するデータブロックの整列補正シフトを実施しています。

Insertion of a TwinPeak object at the beginning of the Rx signal processing chain.

必要な信号処理オブジェクトをコード上で結線して行くPJRC社の作法を取り入れたKeiths' SDRのコーディングスタイルによって、TwinPeakオブジェクトのようなオプション機能を提供するオブジェクトの後付け挿入が容易になっています。コンパイラディレクティブ("W7PUA_I2S_CORRECTION")によって、上記ハードウェアの要件を満たしている場合はTwinPeakオブジェクトへの挿入結線をコンパイラ前処理に指示し、要件を満たしていない場合は点線の迂回結線を指示します。

mainプログラムに対するTwinPeakオブジェクトの動作を下記に示します。左側がsetup()関数とloop()関数から成るArduinoのmainプログラムを、右側がTwinPeakオブジェクトを示します。TwinPeakオブジェクトは、「計測モード」と「実行モード」の2つのモードを持ちます。

TwinPeak object behavior.

setup()関数からTwinPeakオブジェクトを「計測モード」に設定します。この時、上述の矩形波をTeensyのdigital output pin 22から出力します。タイマー等を用いることなく、mainプログラム内で経過アイドル時間を監視して、所定の周期になるように出力を反転させています。Inputオブジェクト経由でSGTL5000コーディックからI2S/DMA転送されてきたデータブロックに対して、欠落シフトの有無/種類を検出し、補正方法を選択します。「計測モード」が完了したら矩形波出力を終了して、TwinPeakオブジェクトを「実行モード」に切換えます。

mainプログラムがloop()関数に制御を移すと、SGTL5000コーディックからのI2S/DMA割込みによってRx信号連鎖を構成する各信号処理オブジェクトのupdate()関数が順番に起動することを、所定のサンプリング周期で繰り返します。「実行モード」にあるTwinPeakオブジェクトのupdate()関数は、「計測モード」で選択された欠落シフト補正をデータブロックに施し、後段の信号処理オブジェクト(I_Switch/Q_Switch)に送出します。

Teensy(14)Keiths' SDRのOutputオブジェクト

Keiths' SDRのRx信号処理連鎖ブロック図

Keiths' SDR(K7MDL局Mike OM版)のRx信号処理連鎖をコードから読み解いて抜き出したもの(α版)を下記に再録します。

Block diagram (alpha version) of the Rx signal processing chain and the Output object under consideration here.

Rx信号処理連鎖の調査も佳境です。今回は、朱色点線内★でマーキングしたOutputオブジェクトを調べました。

前段のAm1_LおよびAm1_Rの調査も行いましが、モノラル信号を2分岐してスカラー倍しているだけです。左右で音量バランスを調整したい場合には有用です。出力段で16bit整数に丸めることを考えれば、スカラー倍のゲインはできるだけ大きくして、アナログAFアンプで音量を調整した方が良いように思います。有限bit長の制限から、SDRでは飽和に対してゲインを上手く調整する必要が生じるかもしれません。

Outputオブジェクト(AudioOutputI2S_F32)

端的に言えば、Inputオブジェクトと逆の処理を行います。ディジタル信号処理したオーディオ信号をコーディックのDACによってアナログ信号に変換するオブジェクトです。

MPUの負荷の時間的偏在によってオーディオ信号のストリームが途切れることを防ぐためか、数々の工夫が見られます。しかし、その設計思想が明示されていないため、解読が難しいオブジェクトでした。

ひとまず、解釈した結果を暫定版として記すことにします。暫定版のデータフローを下記に示します。

Data flow to output audio data (tentative version).

コンストラク

Outputオブジェクト宣言時に、暗黙のうちに実行されるコンストラクタの中でbegin()関数をコールして、ハードウェアの初期化を行っています。MCU(i.MX RT1060)のハードウェア・モジュールを下記に示します。

Hardware module of MCU (i.MX RT1060).

この中で特に重要なモジュールはeDMA(enhanced Direct Memory Access)と思います。ソフトウェアの世界とハードウェアの世界の境界を跨ぐ橋渡しの役割をeDMAが担っています。Rx信号処理アプリが出力したオーディオデータのコーディックへの転送を、CPUの負荷に関係なく独立にeDMAが実行します。

コンストラクタの中のbegin()関数では、以下の順番で初期化を実行しています。

eDMA(1)

最初に、DMAChannelオブジェクトのbegin()関数をコールして、eDMAにチャネルの割付を行っています。

ハードウェアであるeDMAモジュールのTCD(Transfer Control Descriptor)レジスタと対になるソフトウェア側のTCD構造体を用いてレジスタの設定を行っていますが、その設定は複雑なため追跡は断念しました。元々はTeensy販売元のPJRC社が開発したコードを踏襲していると思います。

コーディックに転送する出力データバッファi2s_tx_buffer(16bit整数x2、128ワード)のRAM上のアドレスをTCDに設定しています。出力データバッファi2s_tx_bufferは、Rx信号処理アプリが宣言したRAM上の変数です。アプリの変数の任意のアドレスをTCDに設定することで、アプリのデータをコーディックに転送することが可能になります。この設定が、ソフトウェアとハードウェアの境界の橋渡しになります。

I2S/SAI

Outputオブジェクトのconfig_i2s()関数をコールして、MCUのI2S/SAI(Inter-IC Sound / Synchronous Audio Interface)モジュールの設定を行っています。この関数はサンプリング周波数96kHzを引数に取り、コーディックに供給するClockを生成するMCUのPLLの設定を行っています。I2S/SAIのレジスタ設定も複雑なため追跡を断念しました。非同期通信を行っているらしいことはコメントから分かりました。

確か、Inputオブジェクトのコンストラクタでも同じconfig_i2s()関数をコールしていたはずです・・・? メモリ割り付けを行っていないなら、同じ関数を2回コールしても副作用はないと思いますが、分かり難い印象は残ります。

eDMA(2)

eDMAを起動するハードウェア・イベントとして「DMAMUX_SOURCE_SAI1_TX」(=20)を設定しています。MCU(i.MX RT1060)のデータシートと照合すると、Channel 20番はSAI1(Synchronous Audio Interface 1)モジュールの「SAI TX FIFO DMA Request」に割り付けられています。

DMA転送の要求はコーディックから出されると思っていたのですが、特に該当する信号線は見当たりませんでした。そこで、SAI1(SAI TX FIFO > コーディック)が送信の対象とするSAI TX FIFOバッファが空になると、自動的にeDMA(RAM上のi2s_tx_buffer  > SAI TX FIFO)を起動しているのではないかと推定しています。

NVIC

元々PJRC社が開発したAudioStreamクラスのupdate_setup()関数をコールして、割込コントローラNVIC(Nested Vectored Interrupt Controller)に、Rx信号処理連鎖の更新処理関数software_isr()をソフトウェア割込ベクタIRQ_SOFTWAREに設定しています。

eDMA(3)

DMAChannelオブジェクトのattachInterrupt()関数を用いて、DMA割込に割込サービスルーチンAudioOutputI2S_F32::isr()を割り当てています。eDMAの転送(RAM上のi2s_tx_buffer > SAI TX FIFO)が完了すると、割込が自動的に発生し、Outputオブジェクトのisr()を実行します。アプリが管理する出力データバッファi2s_tx_bufferを前半と後半に分け、それぞれの転送完了で割込を発生させているようです。次のDMA転送データをデータバッファi2s_tx_bufferに準備するのが、この割込サービスルーチンisr()の役割です。isr()の実行内容の詳細は、節を変えて記します。

コーディックはマスタのMCUに対してスレーブの位置付けになっています。MCUのSAI送信(SAI TX FIFO > コーディック)完了(①)からプルされてeDMA転送(RAM上のi2s_tx_buffer > SAI TX FIFO)が起動(②)し、eDMA転送完了(③)からプルされて割込サービスルーチン(RAM i2s_tx_bufferへの次回出力データの充填)が起動(④~⑧)する複雑な流れが見えてきました。

Diagram of the relationship between hardware and software involved in LR audio signal output.

ソフトウェアによる明示的な制御とハードウェアによる暗黙的な制御が絡み合っているため、全体の流れが分かり難くなっています。MCUのデータシートの理解が必要になりますが、データシートは可能なオプションの列挙に等しく、特定の機能の実現方法を理解するようには書かれていません。MCUが複雑で実施できるオプションが多過ぎることが理由の1つかと思います。SDRをコーディングしたOM諸氏も、Teensy開発元PJRC社のコードを可能な限り踏襲して拡張しているようです。

DMA割込サービスルーチンAudioOutputI2S_F32::isr()

  1. eDAMのTCDが指し示すメモリ上の現時点のDMA転送データのアドレス(SADDR:Source Address)を取得します。
  2. 取得したSADDRから、DMA転送用の出力データバッファi2s_tx_bufferの前半を転送中かどうかを確認します。
  3. 現時点で後半を転送中であれば、前回のデータブロックを転送途中と判定し、前半の先頭アドレスを次回充填先アドレスに設定する処理のみを行います。
  4. 現時点で前半を転送中であれば、前回の前半と後半のデータブロックを全て転送完了したと判定し、後半の先頭アドレスを次回充填先アドレスに設定します。
    続けて、update_all()関数をコールして割込コントローラNVICに対してソフトウェア割込ベクタIRQ_SOFTWAREを保留(PENDING)に設定します。この処理はInputオブジェクトでも実施していました。追跡できていませんが、InputとOutputの両方が完了するまで、更新処理を保留(PENDING)にしているのかもしれません。
  5. DMA転送用出力データバッファi2s_tx_bufferの次回充填先アドレスに出力データを充填します。この時に、32bit浮動小数点データを16bit整数データに型変換し、LチャンネルとRチャンネルのデータを合わせて32bitバッファに充填します。
  6. CPUのデータキャッシュをフラッシュして、キャッシュの内容をメモリに書き込みます。DMA転送の対象はメモリだからです。
  7. 出力データの前半をDMA転送用出力データバッファi2s_tx_bufferに充填したかどうかを調べます。
  8. 出力データの前半の充填が完了しているなら、出力データの後半の充填を次回に備えて設定します。
  9. 出力データの後半の充填が完了しているなら、次回に備えて、予備の2ndデータブロックblock_left_2ndとblock_right_2nd(のアドレス)を出力データblock_left_1stとblock_right_1st(のアドレス)に複写し、2ndデータブロック(のアドレス)をNULLに設定します。
    このような複雑な構成にした設計思想は不明ですが、データブロックを1stと2ndの2段構成にするのは、MPUの負荷の時間的偏在によってオーディオ信号のストリームが途切れることを防ぐためと推測しています。

update()関数による更新処理

上記DMA割込サービスルーチンのステップ4において、前半と後半のデータブロックを全て転送完了した場合は、更新処理を実行するsoftware_isr()関数を割り付けたソフトウェア割込ベクタIRQ_SOFTWAREを保留設定していました。保留が解ければ、全てのRx信号処理連鎖が更新され、Outputオブジェクトも更新されます。その更新内容を定義しているのが、このupdate()関数になります。

update()関数では、Rx信号処理連鎖の前段(オーディオ・ゲイン処理)の処理結果のデータブロックをQueueから取得します。LチャンネルとRチャンネルのデータを別々に処理します。16bit整数のスケール変換を行い、Double bufferの2ndデータブロックに格納します。スケール変換を行っただけで、型は32bit浮動小数点です。

update()関数の役割はここまでです。Double bufferから先のデータ転送は、前述したDMA割込サービスルーチンAudioOutputI2S_F32::isr()の役割になります。

感想

以上、Outputオブジェクトの全貌を理解するには、MCUのデータシートのレジスタ設定に精通する必要があります。SDRの改良や実験を行う上で、当面、それは必須ではないと思います。

RX信号処理連鎖のInputオブジェクトとOutputオブジェクトはファームウェアと見做し、その他をアプリケーション・ソフトウェアと見做して、信号処理アプリの改良実験に専念するのが良いかと思います。

 

RX信号処理連鎖の調査は今回で終了です。次回は、"Twin Peaks"問題の調査結果をまとめたいと思います。