非職業的技師の覚え書き

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

RS-HFIQ(13)Quisk IQバランス校正(1)

動機

RS-HFIQのBIT(内臓テスト)機能をQuiskに実装した動機はIQバランスの校正です。ダイレクトコンバージョン方式のSDRの場合は、送信も受信もアナログ回路の部品公差の管理だけでイメージ抑圧を達成するのは困難であり、IQバランスの校正が性能を左右します。

RS-HFIQの場合、アナログ回路の調整箇所はありません。IQバランスの校正はSDRソフトウェア側で対応する必要があります。ソフトウェアの方がアナログ回路よりも柔軟な校正ができるはずです。

QCX振り返り

ここで、IQバランスの校正を既に経験したQCX+ 5W CW transceiver kitを振り返るのも、アナログTransceiverとSDRの比較という観点で有益と思います。

QCX+ 5W CW transceiver kit

QRP Labs社のQCXはマイコン制御のアナログCW Transceiverですが、受信部にはQSD(直交検波器)を採用し、RF信号をAFトーン信号にダイレクトコンバージョンしています。受信IQオーディオ信号の合成によるイメージ抑圧は、オペアンプによるアナログ位相シフトと加算で実現しています。

Block diagram of QCX+ with IQ balance adjustment points commented in light blue.

位相シフタ回路には可変抵抗による2ヵ所の位相シフト調整箇所があり、CWフィルタ回路の加算入力部にも可変抵抗による振幅バランス調整箇所が設けられています。位相シフト調整箇所が2ヵ所設けられている理由は、オーディオ周波数の高域と低域の調整に対応するためです。

下記NA5Y局OMのYouTube(6:00頃から)にオシロスコープを用いたQCX(初期機種)のIQバランス校正のデモがあり、QCX+組立時に参考にさせて頂きました。

www.youtube.com

QCXのソフトウェアはQRP Labs社の非公開IPとなるため詳細は不明ですが、Si5351Aを活用したBIT機能が組み込まれており、マニュアルに従って操作すればIQバランスの校正を行うことが出来ました。もしBIT機能が無かったとしたら、イメージ抑圧の性能はかなり劣化したのではないかと想像されます。

QuiskのIQバランス校正

校正対象範囲

QCXで振り返ったように、IQバランスの校正はオーディオ周波数帯域の全域で行う必要があります。さらに、Quiskのドキュメント「Quadrature Mixer Corrections」には、各バンド個別にバンド周波数全域で行う必要がある旨の記載があります。

さすがに全域で校正データを隈なく収集することは困難なため、Quiskには校正線の補間機能が実装されているようです。要所を数点校正すればSaveしたデータから校正データを補間してくれるようです。

QCXの場合は高域と低域を調整すれば、アナログ回路の連続特性からオーディオ周波数全域の校正をカバーできました。一方、Quisk SDRはディジタル補間によって同様の全域校正を実現していることになります。

校正方法

受信模擬信号を生成可能なRS-HFIQ BIT機能の制御パネルをQuiskに実装したため、少なくとも受信部については自動校正が最終目標です。

一方、QuiskにはGUIのスライダを用いたIQバランス手動調整機能が提供されています。まず、その機能を用いて校正を試行し、感度を体感することにしました。

校正画面呼び出し

Procedure for opening the IQ balance calibration screen.

①Configボタンのクリック、②Configタブのクリック、③Rx Phase..ボタンのクリックで、受信IQバランス校正画面が開きます(下図参照)。送信IQバランス校正画面はその下のボタンで開きます。

USB側BIT信号注入

VFO(LO)= 7,020KHzに対してUSB側に7,021KHzのBIT信号を注入しました。IQバランス校正前の状態を下記に示します。

Image signal status before IQ balance calibration when a BIT signal of 7,021 KHz on the USB side is injected against VFO 7,020 KHz.

VFO = 7,020KHzを挟んで逆サイドのLSB側にイメージが認められ、その強度は約-40dBcになります。ノイズレベル-90dB(-70dBc)に対して十分大きな信号強度になります。

なお、第3高調波、第7高調波、第11高調波も認められます。これらはイメージを抑圧しても存在することから、イメージ信号の高調波ではないことが確認できました。Si5351Aが発生するBIT信号が矩形波であることに起因して、どこからか回り込んでいるのではいかと考えています。奇数次が全て発生していない理由は不明です。

上記画像の下側のパネルがIQバランス校正用画面です。スライダーが4本あり、全て中央位置に初期化されています。上から、(A1)振幅精密調整、(A2)振幅粗調整、(P1)位相精密調整、(P2)位相粗調整の各スライダーです。これらのスライダーを動かしてイメージ抑圧を図りました。

USB側BIT信号のLSB側イメージ抑圧の試行

(A2)振幅粗調整、(P2)位相粗調整、(A1)振幅精密調整、(P1)位相精密調整の順番にスライダーを操作してイメージ抑圧を図りました。合理的な校正GUIであることが体感できました。

Image signal status after IQ balance calibration when a BIT signal of 7,021 KHz on the USB side is injected against VFO 7,020 KHz.

イメージをノイズフロアから時々頭を出すレベル-85dB(-70dBc)にまで抑圧できました。振幅の補正量は-0.008030、位相の補正量は0.678354(単位不詳)でした。

高調波の強度は-50dBc以下ですが、イメージ信号の強度変化とは関係なく、そのままの強度で残っていることが確認できます。

LSB側BIT信号注入

そのままの状態で、VFO(LO)= 7,020KHzに対してLSB側に7,019KHzのBIT信号を注入しました。IQバランス校正前の状態を下記に示します。

Image signal status before IQ balance calibration when a BIT signal of 7,019 KHz on the LSB side is injected against VFO 7,020 KHz.

VFO = 7,020KHzを挟んで逆サイドのUSB側にイメージが認められ、その強度は約-32dBcになります。前記のLSB側のIQバランス校正はUSB側に対しては効果が無い、あるいは逆効果をもたらしていることになります。

LSB側BIT信号のUSB側イメージ抑圧の試行

Image signal status after IQ balance calibration when a BIT signal of 7,019 KHz on the LSB side is injected against VFO 7,020 KHz.

LSB側と同様に、USB側もイメージをノイズフロアから時々頭を出すレベル-85dB(-70dBc)にまで抑圧できました。振幅の補正量は0.022506(LSB側-0.008030)、位相の補正量は0.591768(LSB側0.678354)でした。

USB側の位相の補正量はLSB側に対して13%の違いに留まりますが、振幅の補正量は符号が逆転していることがわかります。1セットの補正量では両サイドに対応できないことが確認できました。

USB側BIT信号再注入

Image signal status after reverse side IQ balance calibration when a 7,021 KHz BIT signal is re-input on the USB side for a VFO of 7,020 KHz.

元に戻ってUSB側に7,021KHzにBIT信号を再注入すると、校正前よりも強度の大きい-36dBc(元は-40dBc)のイメージ信号が確認されました。振幅の補正量が望ましい値よりも逆側に調整されているためと思われます。

計画

以上の試行により、複数点でIQバランス校正を行い、各点で適切な校正を適用する必要があることが分かりました。

今後、Quiskの校正点記録方法、校正量補間方法を調査し、補間校正性能を評価したいと思います。

RS-HFIQ(12)Quisk(Linux版)設定(続)

Pi 400 SoC の追加調査

Raspberry Pi 400 は Pi 4Bと同じBroadcom社製SoCのBCM2711(Quad-core Cortex-A72 64-bit SoC)を搭載していますが、クロック周波数は異なっています。その理由は放熱板の有無と考えていたのですが、どうやら「Stepping level」が違うらしいということが分かりました。
Stepping level」とは直訳では意味を捉え難い言葉ですが、意訳すると「露光マスク改訂番号」という意味合いになるようです。半導体ウェハ全面にステップ動作を反復して回路パターンを焼き付ける露光機をStepperと呼称していたことから来ているようです。ただし、現在の先端露光機は液浸Scanner、最先端露光機はEUV露光機ですので、言葉が時代に置いて行かれた感があります。プロセスルール28 nmとされるBCM2711はScannerで露光されていると推測します。

以下はWeb上の二次情報からの受け売りです。
Pi 400 と Pi 4B は同じSoC(BCM2711)を採用していますが、チップに刻印されたモデル番号を確認すると前者は2711ZPKFSB06C0T、後者は2711ZPKFSB06B0Tであったことが報告されています。後尾の「C0」と「B0」が Stepping level(~露光マスク改訂番号)とされています。最初のアルファベットがベース(トランジスタ)レベルの改訂番号、次の数値がメタル(配線)レベルの改訂番号とのこと。つまり、初期の Pi 4B に対してPi 400 はベース(トランジスタ)レベルを改訂した露光マスクで製造したSoCを搭載していることになります。
改訂の中身が問題になりますが、幾つかある中に「Power gating」(Clock gatingとする説もあり)が挙げられていました。使用していない回路への電力供給(あるいはクロック供給)をOFFにする機能です。チップ発熱の主な要因にトランジスタの漏れ電流(ゲートをLowにしても流れる電流)がありますので、使用していない回路への電力供給(あるいはクロック供給)をOFFにすればそれだけ発熱が減り、熱設計が容易になり、クロック周波数を上げられることにつながります。
ただし、Power gatingには制御回路が必要になると思われるため、メタル(配線)レベルが改訂されていないことが腑に落ちません。元々組み込まれていたPower gating機能がベース(トランジスタ)レベルの不具合によって上手く機能していなかったのに対して、改訂後に機能するようになった・・・ということでしょうか。

改訂前のSoCは在庫が捌け次第に市場から姿を消すと思われます。既に、Pi 4Bの箱を開けたら「C0」が載っていたという報告もあるようです。Raspberry Pi の製品型番が同じであればクロック周波数は変わらないと思いますが、放熱対策が容易になることやオーバークロックへの余力が増す利点があるかと思います。

RS-HFIQ BIT制御パネルの改良

方針

Linux版QuiskでBIT(内臓テスト)制御パネルを開くとIQサンプリングが完全に停止するという気付きがありました。そこで、BIT制御パネルを開く関数を呼ぶ際に並列プロセスを立ち上げて、Quiskメインパネルと並列に動作させることにしました。

Pythonのプロセスベースの並列処理ライブラリmultiprocessingには、並列プロセスを起動する次の3種類の方法がサポートされています。

  1. spawn: WindowsmacOS で標準、Unixでも利用可
  2. fork: Unixで標準
  3. forkserver: Unixで利用可

子プロセスのクラッシュを引き起こす可能性に対して、spawnの方がforkより安全であるとされています。そこで最初にspawnを試しましたが、RS-HFIQを制御するhardwareオブジェクトを子プロセスに引数として渡す際にエラーが発生したため、使用を断念しました。昔憧れた(MS-DOSや初期のWindowsには並列プロセスを生成する仕組みが無かった・・・)Unix標準のforkを使用することにしました。

実装

BIT制御ボタンの押下イベントに呼応するコールバック関数を実装したwidgets_rshfiq.pyファイルを改良します。

ファイルの先頭で並列処理ライブラリmultiprocessingをインポートします。

from multiprocessing import Process

BottomWidgetsクラスのコールバック関数OnBtnRSHFIQを、並列処理プロセスを起動するように書き換えます。

## callback function of the added button to open RS-HFIQ control panel.
def OnBtnRSHFIQ(self, event):
    print('OnBtnRSHFIQ() called back with event', event)
    #lib_rshfiq.control_panel(self.hardware)
    ## Process-based parallelism --------------------------------------
    p = Process(target=lib_rshfiq.control_panel, args=(self.hardware,))
    p.start()
    p.join(timeout=1)

lib_rshfiq.control_panelがBIT制御パネル用に作成したクラスのコンストラクタ関数、self.hardwareがRS-HFIQ制御オブジェクトです。このオブジェクトがシリアルポートを開いて保有しているため、BIT制御パネル関数に渡すことが必須です。
並列処理Process関数は明示的に並列プロセス起動方法を指定しなければ、Linux環境ではディフォルトでforkシステムコールを採用します。これによってQuiskプロセスから並列分岐し、p.startでBIT制御プロセスを開始します。p.joinで引数のtimeout=1秒だけ親プロセスをブロックし、1秒後に並列動作を開始します。
p.joinは不要かもしれませんが安全弁です。オブジェクトのステータスを更新するバックグラウンド機構のために必要とされているようです。

結果

Quisk (Linux version) test scene.
Test results for parallel processing of the RS-HFIQ built-in test control panel.

目論見通り、BIT制御パネルを起動してもQuiskのサンプリングプロセスが途切れることは無くなりました。BIT制御設定も即座にQuiskのスペクトルに反映されます。Windows環境で共有ライブラリのOmni-Rigを使用した場合と同じパーフォーマンスになりました。
気付きがありました。Quiskパネルの最下段左の「RSHFIQ」ボタンは、以前はBIT制御パネルを閉じるまで押下状態を維持していました。しかし、今回はプロセスの並列化によって、p.joinで指定した1秒後に押下可能な状態に復帰します。実際、複数のBIT制御パネルを起動することが出来てしまいました。ここは排他処理の仕組みを入れるべきかもしれません。

Raspberry Pi OS の Task Manegerで調べると、2つのPythonプロセス(図中のPID=1989とPID=2004)が起動していました。前者が親プロセス(Quiskパネル)で、後者が子プロセス(BIT制御パネル)です。前者のCPU使用率は11%、後者はBIT設定の待機状態のため0%でした。他のプロセスを合わせた合計でも19%であり、シングルコアで賄える処理内容となっています。Power gatingの恩恵によって、シングルコアのみに電力を供給し、他の3つのコアへの電力を遮断して発熱を抑えているものと思います。
Pi 400の能力には余力があるため、WSJT-Xも起動してマルチコアを使用する様子を見てみたいところです。WSJT-XとQuiskの接続設定はこれからの課題です。

電鍵シリアル接続ケーブルの本組

工作

A1 CLUBの「CW HANDBOOK」(pp.52-53)に紹介のある「DitDah-ChatをやるためのUSBシリアル・ケーブルの作成方法」を参考に、電鍵をPC上のQuisk SDRに接続するためのシリアルケーブルを作成しました。

BOM(部品構成表)を下記に示します。全て通販A社でそろえたため、CW HANDBOOK記載の参考価格より割高になってしまいました。

BOM for serial cable assembly to connect CW keyer to Quisk SDR on PC.

部品選定で秀逸な点は、電鍵を接続する3.5mmステレオジャックがD-SUBハウジングケースのケーブル引き出し穴の奥にあるネジボスの間に上手く嵌合する点です。実際はネジボスの間隔が少し狭いので、ハウジングケースをネジ締結する時の仮組に力を要します。ステレオジャックが付くことにより、既存の電鍵ケーブルの抜き差しが可能になります。

Wiring and assembly in the housing.

D-SUBコネクタの裏面に小さいモールドで端子番号が振ってあるため、確認して間違えないようにします。ステレオジャックも同様ですが、Tip/Ring/Sleeveの配線はKeyer側の回路に合わせます。

D-SUBのメス側コネクタにはオス側のネジを受けるスペーサを付ける必要がありますが、D-SUBハウジングケースには付属していませんでした。オスーメス両側がネジになってしまうため、適切なスペーサを何かのついでに調達する必要があります。もっとも、ネジで嵌合しなくても金属部分の嵌合だけで、アマ仕様としては十分な締結保持強度が出ました。

設定

USBデバイスを検索すると、CH340が2件検索されました。この情報だけでは区別がつきません。

$ lsusb
・・・
Bus 001 Device 007: ID 1a86:7523 QinHeng Electronics CH340 serial converter
・・・
Bus 001 Device 005: ID 1a86:7523 QinHeng Electronics CH340 serial converter
・・・

Linuxカーネルが起動時に出力したメッセージを調べました。ポート番号ttyUSB0とttyUSB1が割り当てられていますが、ここでも区別がつきません。搭載チップが同じだと区別がつかないことが分かりました。Quiskが正常起動するかどうかによって、ポート番号が正しいかどうかを判断するしかなさそうです。

$ dmesg
・・・
[    9.789245] usbcore: registered new interface driver ch341
[    9.789346] usbserial: USB Serial support registered for ch341-uart
・・・
[    9.789471] ch341 1-1.2.1:1.0: ch341-uart converter detected
[    9.843337] usb 1-1.2.1: ch341-uart converter now attached to ttyUSB0
・・・
[    9.843637] ch341 1-1.2.3:1.0: ch341-uart converter detected
[    9.853426] ch341-uart ttyUSB1: break control not supported, using simulated break
[    9.853676] usb 1-1.2.3: ch341-uart converter now attached to ttyUSB1
・・・

実は最初は、ttyUSB0がCW Key接続、ttyUSB1がRS-HFIQ接続になっていたため、ハブのポート位置を差し換えました。上記は差し換え後の状態です。ハブの物理的ポート位置と論理的ポート番号の間の法則は見いだせていません。経験上、法則は無いように見えます。

CW Key接続のポートttyUSB1について「break control not supported, using simulated break」と表示されている点が気になります。

試験

Windows版と同様にLinux版QuiskのCW設定を行い、USBシリアルのハンドシェイク信号のDTR-CTS間のループバックのON/OFF試験を行いました。結論として、Quiskは反応しませんでした。

落穂拾い

Windows版で実績のあるFTDI USBシリアル変換アダプター Rev.2 (スイッチサイエンス)に換えたところ、問題なく動作しました。Linux版Quiskの設定に問題はないことが切り分けられました。
こちらのUARTチップはFT231Xです。CH340(ch341-uart converter)チップのドライバのサポートに問題があるのでしょうか。同じチップを採用したRS-HFIQのAruduino Nanoとは問題なく通信できています。複数のCH340チップを同時には扱えないとなると厄介です。
上記メッセージ「break control not supported, using simulated break」を検索すると、同じ問題に直面した複数の人がいることが分かりました。Windowsでは問題なくてもLinuxで顕現することもあるようです。複数の異なる要因で当該メッセージが出る様子であり、簡単には要因を切り分けられそうにないことが分かりました。FTDI USBシリアル変換アダプタを使うことが簡単な解決方法になりそうです。

RS-HFIQ(11)Quisk(Linux版)設定

前回に引き続きRaspberry Pi 400上でQuiskを立ち上げます。

追加インストール

Linux標準装備のテキストエジッタだけでは心許ないため、Pi 400にVisual Studio CodeVSCode)をインストールしました。下記コマンドで簡単にインストールできました。

sudo apt install code

また、Windows PC上のVSCodeにRemote-SSH拡張を導入し、Pi 400のファイルを遠隔編集できるようにしました。VSCodeにこのような拡張機能があるとは知りませんでした。当面は、Pi 400ネイティブのVSCodeに出番は無いかもしれません。

Visual Studio Code on a Windows PC with SSH connection to Raspberry Pi 400.

Quiskのハードウェア設定

RS-HFIQ用ハードウェアファイルの転送

Pi 400にインストールしたQuiskのフォルダに、Windows PC上で検討してきたRS-HFIQ用のハードウェアファイルをまとめたフォルダを転送し、Linuxに適合させる修正を加えます。
フォルダrshfiqの中身は以下の3つのファイルです。

  1. hardware_rshfiq.py: RFフロントエンドのLOやPTTを制御するRS-HFIQ向け専用のCAT関数群
  2. widgets_rshfiq.py: RS-HFIQ専用のQuisk GUI拡張(内臓テスト機能用GUI
  3. lib_rshfiq.py: 内臓テスト機能用ライブラリ

USBデバイスの探索

RS-HFIQのシリアルCATおよびIQオーディオ信号はUSBでPi 400に接続します。Quiskに接続先を設定するためには、それらデバイスの番号あるいは名前を事前に調べる必要があります。

lsusb
ターミナル ウィンドウを起動して、まず、USBデバイスを検索しました。

$ lsusb
Bus 002 Device 002: ID 2109:0817 VIA Labs, Inc. USB3.0 Hub             
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 04d9:0007 Holtek Semiconductor, Inc. Raspberry Pi Internal Keyboard
Bus 001 Device 006: ID 1a86:7523 QinHeng Electronics CH340 serial converter
Bus 001 Device 005: ID 0d8c:8810 C-Media Electronics, Inc. USB Advanced Audio Device
Bus 001 Device 003: ID 2109:2817 VIA Labs, Inc. USB2.0 Hub             
Bus 001 Device 002: ID 2109:3431 VIA Labs, Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Pi 400内部の接続デバイスも、外部の接続デバイスも、論理的(電気的)には区別が無いため混在して出力されます。
Bus 002がUSB3.0、Bus 001がUSB2.0のようです。RS-HFIQ関連のUSB接続をまとめた外部ハブをPi 400のUSB3.0ポートに物理的に挿入したのですが、USB2.0のデバイスしかないためか論理的接続先はBus 001のUSB2.0になっているようです。
Bus 001のUSB2.0のデバイスはHubを除くと、下記の3つです。

  1. Device 004: Holtek Semiconductor, Inc. Raspberry Pi Internal Keyboard
  2. Device 005: C-Media Electronics, Inc. USB Advanced Audio Device
  3. Device 006: QinHeng Electronics CH340 serial converter

USB Sound CardにはHobbyPCB社推奨のStarTech社ICUSBAUDIO2Dを使用しています。StarTech社ホームページの技術仕様から、搭載しているチップセットは「Cmedia CM6533」であることが確認できます。Device 005は、StarTech社の名前ではなくUSBオーディオチップメーカの台湾C-Media社の名前で検索されていますが、USB Sound Cardと見て間違いないでしょう。問い合わせに応答するのは機器ではなくその中のチップになるため、搭載されているチップを把握しておく必要があります。
一方、RS-HFIQのコントローラであるArduino Nanoが搭載しているUSBチップは、ホームページの回路図からはFT232RLとなっていますが、検索したデバイスの中にFT232RLはありません。おそらく、RS-HFIQのArduino NanoはFT232RLの代わりにCH340を搭載した互換品なのでしょう。RS-HFIQのUSBシリアルデバイスはDevice 006と見て間違いないと思われます。
ちなみに、同じHobbyPCB社から先日購入したIQ KeyerのArduino Nanoのパッケージに添付されたバーコードを検索したところ、互換品のGeekcreit社のATmega328P Nano V3 Moduleが検索されたため、RS-HFIQも同様の互換品を採用しているものと推定されます。

dmesg
ここでdmesgにより、Linuxカーネルが起動時に出力したメッセージからRS-HFIQと接続するシリアルポート番号を調べます。

$ dmesg
(前略)
[   11.760118] usbcore: registered new interface driver usbserial_generic
[   11.760223] usbserial: USB Serial support registered for generic
[   11.772218] usbcore: registered new interface driver ch341
[   11.772305] usbserial: USB Serial support registered for ch341-uart
[   11.772448] ch341 1-1.2.3:1.0: ch341-uart converter detected
[   11.788004] usb 1-1.2.3: ch341-uart converter now attached to ttyUSB0
(後略)

usbserialとしてch341-uart converterが検出され、シリアルポート番号ttyUSB0が振られたことが確認できます。hardware_rshfiq.pyファイルのシリアルポート番号をttyUSB0に変更します。

serialport.port = "/dev/ttyUSB0"

これで、シリアルポートオープン試行のtry - except例外処理をクリアーして、Quiskが立ち上がるようになります。ここからは、Quisk上でのSound設定に移ります。

オーディオデバイスの探索

LinuxのSoundの扱いには不慣れです。LinuxのようなOSは、ユーザーアプリの1つが直接ハードウェアにアクセスすることを良しとしないため、デバイスドライバもしくはオーディオサーバを介してアクセスることになります。Quiskは、PulseAudio、PortAudio、または ALSA を使用してサウンド カードにアクセスできるとのこと。至れり尽くせりですが、選択肢の多さは初心者には混乱の元でもあります。

aplay -l
まず、再生デバイスのリストを検索しました。

$ aplay -l
**** List of PLAYBACK Hardware Devices ****
card 0: vc4hdmi0 [vc4-hdmi-0], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 1: vc4hdmi1 [vc4-hdmi-1], device 0: MAI PCM i2s-hifi-0 [MAI PCM i2s-hifi-0]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: Device [USB Advanced Audio Device], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0
card 2: Device [USB Advanced Audio Device], device 1: USB Audio [USB Audio #1]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

Pi 400は映像と共に音声も扱えるHDMIポートを2つ備えているため、card 0とcard 1はHDMIになっています。ちなみに、Pi 400ではオーディオジャックが廃されているため、音声出力はHDMIを利用するか、Sound Cardを追加する必要があります。
card 2が2つあり、USB Advanced Audio Deviceの名前を持つの2つのデバイス(device 0とdevice 1)があります。これがUSB Sound Cardで、片方が入力デバイス、もう片方が出力デバイスと思いますが、この時点では割り付けは不明です。

arecord -l
次に、録音デバイスのリストを検索しました。

$ arecord -l
**** List of CAPTURE Hardware Devices ****
card 2: Device [USB Advanced Audio Device], device 0: USB Audio [USB Audio]
  Subdevices: 1/1
  Subdevice #0: subdevice #0

マイク入力用(QSD用)のデバイスは、card 2のdevice 0であろうとの当たりが付きました。ヘッドフォン出力用(QSE用)のデバイスは、残るcard 2のdevice 1ということになります。

cat /proc/asound/cards
次に、cardsファイルの中身を調べました。

$ cat /proc/asound/cards
 0 [vc4hdmi0       ]: vc4-hdmi - vc4-hdmi-0
                      vc4-hdmi-0
 1 [vc4hdmi1       ]: vc4-hdmi - vc4-hdmi-1
                      vc4-hdmi-1
 2 [Device         ]: USB-Audio - USB Advanced Audio Device
                      Speed Dragon USB Advanced Audio Device at usb-0000:01:00.0-1.2.2, full speed

有用な追加情報は得られませんでした。

python portaudio.py
次に、Quiskに附属するユーティリティプログラムportaudio.pyを用いて、使用可能な PortAudio 名のリストを検索しました。

$ python portaudio.py
(前略)
Version 1246720
Version Text b'PortAudio V19.6.0-devel, revision 396fe4b6699ae929d3a685b3ef8a7e97396139a4'
NumDev 4
Device  0, host api b'ALSA'
    Name b'USB Advanced Audio Device: Audio (hw:2,0)'
    Max inputs 2,  Max outputs 2
Expression 'ret' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 1812
    Speeds for 2-channel paInt32:   44100   48000 
Device  1, host api b'ALSA'
    Name b'USB Advanced Audio Device: Audio #1 (hw:2,1)'
    Max inputs 0,  Max outputs 2
    Speeds for 2-channel paInt32:   44100   48000 
Device  2, host api b'ALSA'
    Name b'pulse'
    Max inputs 32,  Max outputs 32
    Speeds for 2-channel paInt32:   44100   48000   96000   192000 
Device  3, host api b'ALSA'
    Name b'default'
    Max inputs 32,  Max outputs 32
    Speeds for 2-channel paInt32:   44100   48000   96000   192000 
Close 0

Device 1「USB Advanced Audio Device: Audio #1 (hw:2,1)」がステレオ出力(Max inputs 0, Max outputs 2)、すなわちヘッドフォン出力用(QSE用)のデバイスであることが確認できました。残念ながら、Speedsは48KHzまでとなっています。96KHzはWindowsしかサポートしていないのかもしれません。
また、Device 0「USB Advanced Audio Device: Audio (hw:2,0)」がステレオ入力(Max inputs 2, Max outputs 2)、すなわちマイク入力用(QSD用)のデバイスであることも確認できます。ただし、Device 0がステレオ出力も備えていることは謎です。エラーも出ているようです。
StarTech社ICUSBAUDIO2Dに搭載されるC-Media社CM6533チップのブロック図を下記に示します。

Block diagram of C-Media CM6533 chip in StarTech ICUSBAUDIO2D.

このチップは入力から出力へのパススルー経路を持っていることが分かります。もしかしたら、このパススルー経路によってDevice 0が出力も備えていると認識されているのかもしれません。

QuiskのHardware設定

Quisk → Config → *RS-HFIQ* → Hardware設定画面にて、Hardware file path に hardware_rshfiq.py ファイルのパスを設定し、Widget file path に widgets_rshfiq.py ファイルのパスを設定します。

Hardware settings for Quisk.

QuiskのSound設定

Quisk → Config → *RS-HFIQ* → Sound設定画面にて、I/Q Rx Sample Input として「alsa: USB Advanced Audio Device USB Audio (hw:2,0)」をプルダウンから選択します。
また、I/Q Tx Sample Output として「alsa: USB Advanced Audio Device USB Audio #1 (hw:2,1)」をプルダウンから選択します。
注意点として、Rateは48000から変更しないようにします。試しに98000に変更したところ、Quiskがハングアップし、プロセスのKillもできなくなりました。

Sound settings for Quisk.

RS-HFIQ内臓テスト機能による受信テスト

RS-HFIQ内臓テスト機能も問題なくPi 400上で制御できました。

LO - 1KHz

LO(= 7020KHz)に対して、-1KHzの内臓テスト信号BIT(= 7019KHz)を発生させ、Quiskで受信しました。Windows版と同様に、約-40dBc(= -20 + 60 dB)のイメージが発生することが確認できました。

Receive test by Quisk with RS-HFIQ built-in test function (for LO - 1KHz).

LO + 1KHz

LO(= 7020KHz)に対して、+1KHzの内臓テスト信号BIT(= 7021KHz)を発生させ、Quiskで受信しました。Windows版と同様に、約-40dBc(= -20 + 60 dB)のイメージが発生することが確認できました。

Receive test by Quisk with RS-HFIQ built-in test function (for LO + 1KHz).

気付き

Windows版QuiskではBIT(Built-In Test)制御パネルを開いた状態でも間欠的にI/Qサンプリングが並列稼働しましたが、Linux版QuiskでBIT制御パネルを開くとI/Qサンプリングが完全に停止しました。BIT制御パネルで内臓テスト機能の設定を行った後にパネルを閉じると、I/Qサンプリングを再開しました。サンプリングが停止しているのか、あるいはGUIの更新が停止しているだけなのかは不明です。モニタ音を出力できるようになれば明確になると思います。
Windows版Quisk(96KHzサンプリング)よりLinux版Quisk(48KHzサンプリング)の方がLOノイズが小さくなりました。RS-HFIQ内部のQSDの前段にLNAがあるため、アンテナ(ダミーロード)からLOノイズが放射されているとは考え難く、RS-HFIQの筐体あるいはケーブルから放射されていたLOノイズが配置の変化によって小さくなっただけではないかと考えています。
サンプリング周波数が影響したかどうかは不明です。ただし、バンド両端の角状のアーティファクトは消えました。その理由も不明です。また、48KHzサンプリングの帯域は24KHz幅(例えば7008~7032KHz)になるはずですが、約40KHz幅(例えば7000~7040KHz)の帯域の平坦なノイズフロアが表示されます。ノイズだけでなく、7020KHzのLOに対して7000KHzのBIT信号を注入すると、信号強度を損なうことなく表示します。謎は深まるばかりです・・・。

今回はLinux版Quiskの受信テストまで行いました。次回は送信テストに進みたいと思います。

RS-HFIQ(10)Quisk(Linux版)立ち上げ

Raspberry Pi 400の立ち上げ

大型のWindows Desktop PCをSDR運用のために使用するのは宅内移動運用の点で不自由なため、Raspberry Piへの移行に着手しました。Raspberry Pi 4Bは供給が回復基調にあるようですが、まだまだ品薄のためか値段も高目で推移しているようです。もっとも、値段が高いのは円安のためかもしれませんが・・・。
今回はキーボード一体型のPi 400を選択しました。

www.raspberrypi.com

Pi 400のSoC(System on a Chip)はQuad-core Cortex-A72 (ARM v8) 64-bit SoC @ 1.8GHzを採用し、Raspberry Piシリーズの中では最高速クロックの設定になっています。キーボード下の大面積放熱板(重量があります)によって熱設計に余裕があることも寄与していると思います。Pi 400のメモリは4GBで、Raspberry Pi 4Bの最大8GBよりは少ない設定になります。それでも、今まで使用していたRaspberry Pi 3Bの1GBより大幅に増えています。

ここでまたケーブル非互換のトラブルが発生しました。USBのみならず、HDMIコネクタにもmicro、mini、normalの3トリオが存在しています。Raspberry Pi 3Bはnormal-HDMIメスコネクタでしたが、Pi 400はmicro-HDMIメスコネクタの2連装になっています。Pi 400のスターターキットにはmicroオス / normalオスの変換ケーブルが付いていましたが、これではRaspberry Pi 3Bをディスプレイに接続していたnormalオス / VGAメスの変換ケーブルと接続できません。microオス / VGAメスの変換ケーブルか、microオス / normalメスの変換ケーブルが必要になります。年越し中断です。

下記ブランドの変換ケーブルが新年に着荷。1920 X 1200の解像度で問題なく表示できました。

MicroHDMI(male) / VGA(female) conversion adapter.

ところが、VNCでリモート接続すると、最大1920 X 1080までしかディスプレイ設定の解像度選択肢がありませんでした。横より縦の解像度を増やしたいのですが、致し方なしです。

Display at 1920 X 1080 resolution via VNC connection.

WSJT-Xの導入

QuiskはWSJT-Xをサポートしています。CWと共にFT8等のディジタルモードの導入を検討することにしました。
最新のRaspberry Pi OS(Debian version: 11 bullseye)にWSJT-Xを導入するために、Pi 400の性能向上を頼りにソースコードからのビルドを試みました。下記のWeb pageの手順をトレースしたところ、問題なくビルドできました。

linuxhint.com

手順をまとめると以下になります。

  1. Packages Listの更新
  2. 必要なライブラリのインストール
  3. ビルド用フォルダのセットアップ
  4. WSJT-X 2.5.4ソースコード(wsjtx-2.5.4.tgz)のダウンロード
  5. tar(Tape Archive)書庫の展開
  6. WSJT-X 2.5.4のビルド

ビルドの途中で席を外したため、正確な時間は測っていません(戻ってきたら終了していました・・・)が、体感的には30-60分程度でしょうか。Pi 400の消費リソースを時々チェックしたところ、コンパイル中のCPU占有率は25%程度でリンクの時だけ100%に跳ね上がることがある様子でした。コンパイル作業はシングルコアで実行し、ファイル操作が必要なリンク作業はマルチコアに作業が分散しているようでした。メモリは1GBも使用していない様子で余裕がありました。SDカードのアクセス時間がビルド速度を律速しているのではないかと推測しています。WebブラウザChromiumChromeOSS版)の動作も遅いため、Pi 400の性能を引き出すためにはSDカードをSSDに換装する必要があるかも知れません。
実行ファイル「wsjtx」は/usr/local/binに作られます。ビルド直後はメニューに登録されていませんでしたが、再立ち上げするとSound & Videoメニューに登録されました。そこから右クリックでデスクトップにアイコンを配置することも可能です。

Successful build of WSJT-X on the Pi 400.

Quiskのインストール

最新のRaspberry Pi OS(Debian version: 11 bullseye)にWSJT-Xを導入できたことから、OSをダウングレードする必要がなくなりました。このままQuiskのインストールに進みます。
なお、Pi 400のスターターキットに附属するSDカードに書き込み済みのRaspberry Pi OS(Debian version: 11 bullseye)のPythonはディフォルトでPython3でしたので、インストール時に明示的にPython3を指定する必要はありませんでした。

Step 1: Install Required Libraries and Dependencies

Quiskのドキュメントに従い、下記のコマンドで必要なライブラリをインストールしました。

sudo apt-get install libfftw3-dev
sudo apt-get install libasound2-dev
sudo apt-get install portaudio19-dev
sudo apt-get install libpulse-dev
sudo apt-get install python3-dev
sudo apt-get install libpython3-dev
sudo apt-get install python3-wxgtk4.0
sudo apt-get install python3-usb
sudo apt-get install python3-setuptools
sudo apt-get install python3-pip

libfftw3-devライブラリ(Discrete fourier transform)はWSJT-Xのビルド時にインストールしています。他も大多数は最新版をインストール済みでした。実際にインストールが必要だったライブラリは下記の3つです。

  • portaudio19-dev (Portaudio sound library)
  • python3-wxgtk4.0 (wxPython GUI library)
  • python3-usb (Python USB)

Step 2: Linux Source Installation

Quiskの学びの過程でCのソースコードにもアクセスする必要があるため、Quiskもソースコードからビルドしました。ソースファイルの書庫quisk-4.2.14.tar.gzをダウンロードして、下記コマンドでビルドしました。

cd ~/Downloads
tar zxf quisk-4.2.14.tar.gz
cd quisk-4.2.14
make quisk3

問題なくビルドが完了し、Pythonコードからコールする下記の共有ライブラリが作成されました。

_quisk.cpython-39-arm-linux-gnueabihf.so

Completion of Quisk build from source files.

Quisk起動

ディレクトリを移して起動テストを行いました。Windowsと同じ画面が立ち上がりましたが、細部の描写表現が少し異なるようです。

cd /home/amat/quisk
python quisk.py
Quisk (Linux version) startup.

今回はWSJT-XとQuiskのビルドまで実行しました。次回、設定に進みたいと思います。

RS-HFIQ(9)初荷 IQ Keyer

迎春

2023年元旦も雲一つない快晴で富士山が良く見えていました。

Mt. Fuji under clear skies on New Year's Day.

1年前の元旦を振り返ると、13TR-FT8トランシーバ の組立が完了し、保証願書を作成していた頃でした。これとAFP-FSK Transceiver Kitを通して、2022年はFT8の学びが進んだ年でした。
(とは言っても、FT8プロトコルの詳細については積み残しが残っています。新たな学習マテリアルの目星が付いたため、時期を見て再開したいと思います。)
jk1ejp.hatenablog.com

今年はダイレクトコンバージョン方式の送受信SDR(CW、FT8)の学びを完遂することが当面の目標です。非職業的活動(趣味)であることから、目標期日の設定が無いことが良いところです。

初荷

品物

HobbyPCB社のIQ Keyer(Kit)が届きました。SDRのCW送信用のIQオーディオ信号を生成するKeyerです。現在検討中のQuisk SDRおよびTeensy Keith's SDRにおけるCW送信方式のプランBとして購入しました。

Packaging.
Half-finished kit of the contents of the box.

部品はコネクタも含めてPCBにはんだ付けされていました。必要な残作業はAruduino Nanoのはんだ付けとケース組み立てぐらいのようです。ケースパネルとの寸法関係で、Aruduino NanoはPCBへの直付けが必要なようです。
PCBの手前のスペースが大きく空いており、メッセージメモリのボタンを追加できるようです。ケース(カナダ製でした)を決めてから、PCBを設計した結果かもしれません。

輸送実績

HobbyPCB社のホームページは、晩秋になっても長い夏季休暇による不在を表示していましたが、注文は受け付けているようでした。その後、夏季休暇の表示は消えましたが、バックオーダの処理に時間がかかっていたようです。12月下旬になって発送メールが届きました。
郵送オプションは不安がよぎるUSPS一択だったため、郵送グレードを上げて注文しました。やはり米国内輸送は3rdパーティのGlobalPostが担っていたようです。今回は住所の打ち間違いもなく、日本郵政からの注意付箋もありませんでした。「Kanagawa-Ken」が「Kanagawa-K」に短縮された軽微な変更しかありませんでした。住所印字システムが変わったのか、オペレータが習熟したのか、グレードによる輸送品質向上のためか、理由は不明です。

Transportation Results.

輸送経路を追跡すると、NEW YORKからATLANTAまでの北米航空輸送で6日を費やしていることが分かりました。大寒波到来で飛行機が飛んでいなかったのかもしれません。

動作原理

Quisk等のPC SDRとRS-HFIQの間に挿入するIQ Keyerの結線を下図に示します。

IQ Keyer operating principle.

Quiskから出力される送信IQオーディオ信号が、サウンドカードのHeadhoneジャックからRS-HFIQのIQ-IN TXジャックに結線されています(赤線)。IQ Keyerはこの結線の途中に挿入します。通常は、IQ Keyerは送信IQオーディオ信号をバイパスしているだけです。
キー入力があると、IQ Keyerはトーン周波数のIQオーディオ信号を生成して内部の絶縁トランス1次側に入力し、RS-HFIQへの送信IQオーディオ信号を絶縁トランス2次側出力にリレーで切り換えます。
同時に、PTT信号(CW OUT)も生成して、RS-HFIQのKEYジャックにつなげることで、RS-HFIQを送信状態に切り換えます。RS-HFIQのKEYジャックをKeyer入力として使用することは禁止されていますが、PTT入力としては使用できるようです。
IQ Keyerは信号生成タイミングだけをAruduino Nanoのタイマー割込みで制御し、PWM信号からアナログフィルタで正弦波信号を生成しているため、ゼロ遅延として訴求しているようです。

あい路

IQ Keyerにはサイドトーンの調整ノブが付いていますが、ボリューム調整用であり、サイドトーン周波数変更用ではありません。サイドトーンは700Hz(694.4 Hz)に固定されています。SDRにしてサイドトーン固定とは先祖帰りのような気がしますが、タイマー割込み180uS(5.55555 kHz)と密接に関係しているようです(5.55555 kHz / 8 updates/cycle = 694.4 Hz)。PWMクロックとタイマー割込みの整数比の関係を崩すとジッターが発生するとのこと。
サイドトーン周波数を低くする分には、PWMクロックを低くしてタイマー割込み周期を長くする方向に調整することになるため、できそうに思えますが整数比に関する詳細検討が必要です。
IQ Keyerを使用する場合は送信IQオーディオ信号線に乗せるサイドトーン周波数が固定されるため、Tune(同調周波数)に対するLO(SI5351A局部発振周波数)のオフセット同期調整を行うことができるように、Quiskのハードウェアファイルのプログラミングが必要になります。

RS-HFIQ(8)QuiskのCWモード(1)

CWのあい路

Quiskは低遅延のCWが訴求ポイントの1つとのことでしたので、簡単にCW送信ができると思っていました。しかし、先の改造(RS-HFIQ(6)QuiskのTuneとLOの同期制御 - 非職業的技師の覚え書き)が仇となって試行錯誤に時間を費やしました。
SSBの場合は側波帯が復調の対象になるため、仮想搬送波に対するQuiskの同調周波数(Tune)とRS-HFIQの局部発振周波数(LOあるいはVFO)が一致していても問題ないものと思います。
一方、CW受信の場合は搬送波しかないため、受信信号に対するQuiskのTuneとRS-HFIQのVFOを一致させると直交検波器(QSD)の回路が受信信号を検波できなくなり、復調対象のオーディオIQ信号がQuiskに入力されなくなります。また、CW送信の場合は、TuneとVFOを一致させると、QuiskからRS-HFIQの直交変調器(QSE)に入力するオーディオIQ信号をソフトウェアで生成できなくなる仕様になっていました。
CWモードの場合はTuneに対してトーン周波数(600Hz等)の分だけVFOをオフセットさせれば良いと思われますが、Quiskにはそのような機能は備わっていませんでした。LO固定のハードウェアによっては対応できないからかもしれません。RS-HFIQは対応できると思いますが、Split動作への影響等を調べる必要があるため、TuneとVFOの同期制御を一旦解除して元の非同期制御に戻しました。その調査過程の覚え書きを記します。

電鍵の接続

電鍵接続オプション

Quiskへの電鍵の接続方法としては、多様なSDRハードウェアに合わせて(1)シリアルポート、(2)MIDI、(3)LAN、(4)GPIOと様々なオプションがあるようです。しかし、ドキュメントが無いため、Quiskにどこまで標準実装されていて、どこからハードウェアに合わせて独自にコーディングをする必要があるのかが分かりませんでした。
RS-HFIQ本体のKEYジャックは内部のコントローラのArduino Nanoに結線されていますが、開発元による実装は放棄状態(上手く行かなかった模様)になっているため、RS-HFIQからキーイング信号を取り込む手段はありません。そこで、USBポートをまた一口塞いでしまいますが、電鍵の(1)シリアルポート接続を試みることにしました。
それにしても、PCソフトウェアのSDRはUSB喰らいであることが分かりました。CAT通信、IQ信号、マイク、電鍵と4口も占有します。USBハブを増設しましたが、USB3.0USB2.0を同居させることができないため、完全に集約するには至っていません。また、RF信号モニタ用のSDRplay / SDRuno用のUSBポートを確保しても、接続すると「デバイスが使用中です」の独占競合が発生して調停するのに難渋しました。不親切な警告ダイアログの競合「デバイス」が何かは後述します。

電鍵シリアル接続のConfig設定

Quiskへの電鍵シリアル接続に必要なConfig設定画面を下記に示します。

Configuration settings for serial connection of CW keyer.

以下の手順で設定しました。

  1. *RS-HF-IQ* タグを開く。
  2. Timing and CW タグを開く。
  3. 好みのトーン周波数を設定する。
  4. 電鍵を接続したシリアルポートを設定する。
  5. 接続信号端子(CTSもしくはDSR)を選択し、信号電圧レベルを選択する。

つぎに、Sound設定画面を下記に示します。

Sound setting screen to set the in-phase channel in IQ.

IQへのin-phaseチャネルの割り当ては試行錯誤で探索するしかありませんでした。受信はディフォルトのQチャネルをin-phaseに割り当てましたが、送信は入れ替えてIチャネルをin-phaseに割り当てる必要がありました。入れ替えないとLOを挟んでTuneの逆サイドに送信してしまいます。

電鍵シリアル接続の仮組

手持ちにFT231X(USB to FULL HANDSHAKE UART IC)を用いた「FTDI USBシリアル変換アダプター Rev.2 」(スイッチサイエンス)があったため、電鍵シリアル接続テストのための仮組を行いました。下図写真が変換アダプター、上左がFT231Xチップの応用例、下右がアダプターの回路図です。

Temporary assembly for serial connection test of CW keyer.

変換アダプターが搭載するUART(Universal Asynchronous Receiver/Transmitter)LSIのFT231Xは、RS-232C通信規格のハンドシェイク通信を行う信号線を全て備えています。シリアル通信におけるDATAはプロトコルに則ったビット列になるため、電鍵の開閉を検知するにはハンドシェイク信号を応用します。
ただし、変換アダプターの電気的仕様は、15mの距離を接続するRS-232Cとは異なり、ロジックレベル(3.3V)になっています。上図の上左のRS-232C応用例から分かる通り、電気的仕様を充足するためにはレベルコンバータ(★)が必要になります。上図の下右の回路図から、変換アダプターはロジックレベルのI/Oになっていることが分かります。また、変換アダプターを小型化するためか、あるいは目的の用途(プログラムライターとの通信等)に必要なかったのか、ハンドシェイク信号線はDTRとCTSの2本になっています。よって、QuiskではCTS信号端子を電鍵接続に使用しました。ちなみに、Quiskはエレキーのプログラムは備えていないため、信号端子は1本で足ります。
RS-232Cの信号線と電鍵への割付を下表に示します。Quisk PCはDTE(Data Terminal Equipment:端末装置)の役回りになり、電鍵はDCE(Data Communication Equipment:終端装置)になります。

Assignment of RS-232C signals to CW keyer.

シリアル通信の準備が整うと、Quisk PCはDTR(Data Terminal Ready:データ端末準備完)の信号レベルをHighに設定します。電鍵を挟んでDTR信号端子をCTS(Clear To Send:送信可能)信号端子に接続します。これにより、電鍵を押下する毎にCTS信号がHighレベルになります。
RS-232Cのハンドシェイクの方法は複数あり、プログラムで柔軟に対応できるようになっているようです。そのため、Pythonのシリアル通信ライブラリではハンドシェイク信号のセットやモニタが個別に可能になっています。これにより、QuiskはCTS信号のレベルを監視して電鍵の押下を検出しています。ここまでは、Quiskに実装済みでした。

電鍵接続テスト

QuiskのGUI表示

DTR信号ピンとCTS信号ピンを接続すると、QuiskボタンパネルのTxインジケータのフェイスカラーが赤色に変化しました。このTxインジケータは左隣のPTTボタンによって赤色に変化しますが、電鍵押下時にも赤色に変化することが分かりました。これで、Quiskが設定どおりにCTS信号を監視して、電鍵押下に反応していることが確認できました。

Tx indicator on Quisk button panel that changes face color to red when transmitting.

しかし、RS-HFIQに視線を転じると、PTTボタンでは点灯するTX LEDが電鍵押下では点灯していません。送信モードへの切換えがQuisk内で止まり、RS-HFIQまで届いていないようです。

RS-HFIQ TX LED点灯(送信切換)のためのコードの解析

ハードウェアファイル(hardware_rshfiq.py)には、RS-HFIQを送信状態にする関数としてOnButtonPTT関数しか実装されていません。したがって、電鍵押下の検知からOnButtonPTT関数をコールするまでがコードでつながっていないと、永久にRS-HFIQが送信状態に遷移することはありません。そもそも、OnButtonPTT関数はPTTボタンのコールバックイベント関数なので、つながっていない可能性が濃厚です。そこで、コードの追跡に着手しました。
quisk.pyファイルにSoundThreadクラスが実装されています。GUIのイベントポーリングとは並列に実行されるオーディオIQ信号のサンプリング信号処理の実装ではないかと推測しました。SoundThreadクラスが持つメンバ関数は、コンストラクタ、run関数、stop関数の3つだけです。
run関数の処理内容を下表にまとめます。

Processing details of the run function of the SoundThread class.

信号処理開始の初期化をした後は、終了指示まで永久反復処理を行っています。話題が逸れますが、反復処理の中でwdspライブラリの制御関数をコールしていることに気付きました。NR0V局Warren C. Pratt OMがSDRのために開発したopen-source Digital Signal Processing libraryのWDSPを、他の多くのSDRと同様にQuiskも利用していることが判明しました。
それはさておき、反復処理の中で「CW」のキーワードが入った関数はHardware.PollCwKey関数のみになります。名称からは「CWキーを監視してハードウェアの処理を実行する」と読めました。そこで、ハードウェアファイル(hardware_rshfiq.py)にPollCwKey関数を実装し、OnButtonPTT関数と同様にRS-HFIQを送信状態に切り換えるようにしました。結果は、電鍵を押下しても送信状態に切り換わることはありませんでした。PollCwKey関数は「ハードウェアを介してCWキーを監視する」関数のようです。RS-HFIQには電鍵を接続せず、シリアル通信に接続しているため、今回は関係が無かったようです。
つぎに、着目したのはオーディオIQ信号を読み込んだ後に実行しているapplication.OnReadSound関数です。これは行数が多い関数ですが、途中に以下のコードを発見しました。

    if QS.is_key_down():	# Tx indicator
      if not self.tx_indicator:
        self.tx_indicator = True
        self.pttButton.Tx.TurnOn(True)
    else:
      if self.tx_indicator:
        self.tx_indicator = False
        self.pttButton.Tx.TurnOn(False)

電鍵が押下されていた場合に送信インジケータをTrueに設定しています。ここをコメントアウトすると、上記のQuiskボタンパネルのTxインジケータが反応しなくなりました。このコードがTxインジケータを制御していることが分かりました。しかし、他にやっていることはpttButton.Tx.TurnOn関数にTrueを設定することだけです。詳細は不明ですが、ボタンの属性のようなものを切り換えているだけと判断しました。このコードの中にハードウェアを制御している部分はありません。
さらに読み進めると、次のコードを発見しました。

    if self.want_RxTx:
      x = QS.is_key_down()	# Must be 0 or 1
      if self.old_RxTx != x:
        self.old_RxTx = x
        Hardware.OnChangeRxTx(x)

別のコードにあるwant_RxTxフラグの設定箇所を調べると、Hardware.OnChangeRxTx関数が実装されているかどうかを判定するフラグであることが分かりました。電鍵の押下状態が切り換わったら、電鍵の押下状態を引数にしてHardware.OnChangeRxTx関数をコールしています。この関数がハードウェアの送受を切り換える関数に違いないと推測し、ハードウェアファイル(hardware_rshfiq.py)に以下のコードを実装しました。RS-HFIQのコントローラであるAruduino Nanoに送受切換の「x」コマンドをシリアル送信します。

    def OnChangeRxTx(self, is_tx):
        if is_tx:			# Turn the software key bit on or off
            cmdstr='*x1\r'
        else:
            cmdstr='*x0\r'
        if serialport.isOpen():
            if DEBUG == 1:
                print("Setting Rx/Tx for is_key_down(), cmdstring:  ", cmdstr)
            serialport.write(cmdstr.encode())

これで、電鍵押下に反応してRS-HFIQが送信モードに切り換わるようになりました。後は、IQ信号が適切に出力されていれば、QSE(直交変調器)でRF搬送波信号が生成され、終段アンプから送信されるはずです。
ここまでのCW送信に向けたコード解析およびコーディング結果をまとめると以下となります。

Block diagram of CW transmission with Quisk and RS-HFIQ.

受信トーンを探して

CWモードにおいて、Quiskが同調周波数(Tune)と局発周波数(LO)の関係を制御しているかどうかを、まず受信状態で確認しました。先に導入したTuneとLOの同期制御は切った状態にしました。

Looking for CW receiving tone.

RS-HFIQのLOを7,020,000Hzに設定しました(①)。RS-HFIQのBIT機能を用いて、1,400Hz下方の7,018,600Hzに模擬受信信号を発生させました(②)。QuiskのモードをLSBからCWLに切り換えると(③)、自動的に設定トーン周波数600Hzに応じたRIT(Receive Incremental Tuning)が設定され(④)、TuneをLOより600Hzだけ低域側にシフトさせます(⑤)。これにより、600Hzのサイドトーンを発生させているように見えます(⑥)。

Looking for CW receiving tone (continued).

しかし上図に示す通り、BIT周波数をさらに低域側7,018,600Hzにずらして(⑦)、Tuneで追跡すると(⑧)、TuneとLOの間隔は1,400Hzに広がりますが、サイドトーンは600Hzのまま維持されます。Quisk内部のソフトウェア処理は解析できていませんが、仮想的なVirtual_LOを設定して(⑨)、サイドトーンを発生しているように見えます(⑩)。RS-HFIQのLOとは無関係にサイドトーンを発生していることだけは確かです。

送信トーンを探して

次に、BITをOFFにし、電鍵を押下して送信状態にしました。この時、サウンドカードのHeadphone出力信号(オーディオIQ出力信号)をスピーカアンプに接続して、発生音色をモニタしながらTuneを連続して変更しました。

Looking for CW transmission tone.

受信テストと同様に、RS-HFIQのLOを7,020,000Hzに設定し(①)、QuiskのモードをLSBからCWLに切り換えると(③)、自動的に設定トーン周波数600Hzに応じたRITが設定され(④)、Tuneは7,019,400Hzに設定されます(②)。両者の乖離を600Hzにした状態から送信テストを開始しました。
電鍵を押下して送信状態にすると(⑤)、PCのスピーカからは受信時と同じ600Hzのサイドトーンが発生し、オーディオIQ出力をモニタするスピーカからも600Hzのトーンを聴くことができました(⑥)。Tuneを低い周波数に変えて行くと、オーディオIQ出力のモニタ音は高い音色に遷移して行きましたが、PCのスピーカからは600Hzのサイドトーンが発生したままでした(⑧)。
送信時のサイドトーンはQuisk内部のソフトウェアで処理されているため、RS-HFIQのLOとQuiskのTuneの間の関係変化からは影響を受けないことが分かりました。逆に、送信周波数はRS-HFIQのLOとQuiskのTuneの間の関係だけで決まり、そのオフセット周波数のオーディオIQ信号がQuiskからRS-HFIQに送出されることが分かりました。
モードをLSBからCWLに切り換えることによってQuiskがTuneをシフトさせている理由は、受信時にはLOと一致した受信CW信号からオーディオIQ信号をQSDが出力できないからであり、送信時にはLOと一致した送信CW信号を0HzのオーディオIQ信号(ON/OFF信号)からQSEが出力できないからです。Tuneのシフト量はトーン周波数の600Hzである必然性はなく、サンプリング定理が許す帯域内であれば任意です。これによって、LOを固定したままTuneをサンプリング定理の帯域内で自由に可変することができます。LOと言う名の特異点付きですが・・・。

次に、以下のSDRplay(RSP1A)とSDRunoを用いた次の実験構成で送信周波数を確認しました。RS-HFIQ内部のQSEブロックでオーディオIQ信号(600Hz)がLO(7,020,000Hz)と混合されてRF送信信号(7,019,400Hz)が生成され、BPF、PA、LPFを通過して送信されるはずです(⑦)。

Configuration of the experimental system using SDRplay (RSP1A) and SDRuno to check the transmitted frequency from RS-HFIQ controlled by Quisk.

なお、SDRunoとQuiskを同時に起動しようと試みると、「デバイスが使用中です」と表示されて起動できませんでした。何のデバイスか直ぐには分からなかったのですが、SDRunoもQuiskも復調音をPCから再生するためにスピーカが競合していることが分かりました。Quiskはスピーカのデバイス設定を外しても起動できるため、臨時的にQuiskの復調音を切断しました。

LOを7,020,000Hzに固定し、Tuneのオフセットを低周波数側に-600Hz、-1,200Hz、-1,800Hzと変更し、転じて0Hz、600Hzと変更しました。下記にその結果を示します。上段にQuiskのTune設定を、下段にSDRunoによるRS-HFIQ送信スペクトルの測定結果を示します。

Quisk Tune setting and RS-HFIQ transmit spectrum; (1) Tune = LO - 600Hz.
Quisk Tune setting and RS-HFIQ transmit spectrum; (2) Tune = LO - 1,200Hz.
Quisk Tune setting and RS-HFIQ transmit spectrum; (3) Tune = LO - 1,800Hz.
Quisk Tune setting and RS-HFIQ transmit spectrum; (4) Tune = LO.
Quisk Tune setting and RS-HFIQ transmit spectrum; (5) Tune = LO + 600Hz.

QuiskのTune設定とSDRunoの測定スペクトルの間には30Hzのオフセットがありました。ハードウェアのRS-HFIQとSDRplay(RSP1A)の間のオフセットです。それを考慮すれば、「送信周波数はRS-HFIQのLOとQuiskのTuneの間の関係だけで決まる」ことが確認できました。また、IQ CW方式では、Tune = LO ± 100Hz程度が送信不可の特異点になることも確認できました。
特異点を避けるために、CWモードではTuneとLOのオフセット同期方式を実装することが望ましいと思います。Split操作への影響等を調査して判断したいと思います。

RS-HFIQ(7)QuiskへのRS-HFIQ内蔵テスト機能の実装(続)

動機

ユーザーがGUIボタンをパネルの最下行に追加するクラス(BottomWidgets)がQuiskに準備されていることが、コードの精査から判明しました。このBottomWidgetsクラスをユーザー専用ファイル(widgets_***.py)に定義してConfig設定から読み込むことでGUIを拡張することができます。この方式の利点は、Quiskの基本コードとユーザー専用の拡張コードが混在しないことです。Quiskの基本コードを実装したquisk.pyに手を入れてしまうと、Quiskバージョンアップ時の対応が難しくなります。
そこで、RS-HFIQ専用の内蔵テスト機能をBottomWidgetsクラスに実装し直して、Config設定から読み込む方式に改めました。

BottomWidgetsクラス

ソフトウェアモジュール間の関係

モジュール間の関係を下記に示します。

Relationships between Quisk modules.

インストールしたQuiskのアプリケーションAppクラス(quisk.py)に対して、BottomWidgetsクラス(widgets_rshfiq.py)、RS-HFIQ内蔵テスト用のcontrol_panelクラス(lib_rshfiq.py)、RS-HFIQのHardwareクラス(hardware_rshfiq.py)はユーザーが準備するモジュールです。
なお、DL1KSV局Volker Schroer OMが公開してくれているRS-HFIQ用ハードウェアファイルの名称は「hardware_usbserial.py」でしたが、改造を加えたため、元本と区別するために名称を「hardware_rshfiq.py」に変更しました。ファイル名の接尾語としてハードウェアの名称(rehfiq)を付ける一貫性保持のため、RS-HFIQ内蔵テスト機能制御パネルを実装したファイルの名称を「lib_rshfiq.py」に変えました。BottomWidgetsクラスを実装したファイル名は「widgets_rshfiq.py」です。
Quiskのインストールディレクトリの下に「rshfiq」ディレクトリを作り、これらのファイルを格納しました。QuiskをRaspberry Pi等にインストールした場合も、「rshfiq」ディレクトリを複写するだけで対応できるようになる予定です。(シリアルポート名の変更は必要。)

BottomWidgetsクラスのインスタンス化コードの調査

quisk.pyのアプリケーションクラス(App)の初期化関数(OnInit)の中で、BottomWidgetsクラスのインスタンス化を行っている箇所を下記に示します。ここで追加ボタンを実体化する準備がされているため、ユーザーは必要に応じてBottomWidgetsクラスを実装するだけで済みます。

elif conf.quisk_widgets:
    self.bottom_widgets = conf.quisk_widgets.BottomWidgets(self, Hardware, conf, frame, gbs, vertBox)
if self.bottom_widgets: # Extend the sliders to the bottom of the screen
    try:
        i = self.bottom_widgets.num_rows_added # No way to get total rows until ver 2.9 !!
    except:
        i = 1
    rows = self.widget_row + i
    for i in self.slider_columns:
        item = gbs.FindItemAtPosition((0, i))
        item.SetSpan((rows, 1))

なお、ボタンを追加した後に、ボタンパネルの行数を取得してスライダの長さを決めていることが分かります。これにより、ボリュームスライダ等の長さがボタンパネルの高さの変化に追従して伸長することができます。

BottomWidgetsクラスへの追加ボタンの実装

追加したRS-HFIQ内蔵テスト機能起動ボタン(RSHFIQ)の実装例を下記に示します。BottomWidgetsクラスのコンストラクタ(__init__)がhardwareインスタンスを引数に取るため、アプリケーションクラスでインスタンス化したRS-HFIQのhardwareクラスをRS-HFIQ内蔵テスト機能制御パネル(lib_rshfiq.control_panel)に引き渡し、RS-HFIQのSI5351Aを制御することができます。

# This module is used to add extra widgets to the QUISK screen.

from __future__ import print_function
from __future__ import absolute_import
from __future__ import division

import wx, time
import _quisk as QS

from rshfiq import lib_rshfiq  ## added for RS-HFIQ control panel

class BottomWidgets:	# Add extra widgets to the bottom of the screen
    def __init__(self, app, hardware, conf, frame, gbs, vertBox):
        self.config = conf
        self.hardware = hardware
        self.application = app
        self.correct_screen = None

        self.num_rows_added = 1
        start_row = app.widget_row       # The first available row
        start_col = app.button_start_col # The start of the button columns

        ## A plain push button widget to open RS-HFIQ control panel.
        b = app.QuiskPushbutton(frame, self.OnBtnRSHFIQ, text='RSHFIQ')
        gbs.Add(b, (start_row, start_col), flag=wx.EXPAND)

    ## callback function of the added button to open RS-HFIQ control panel.
    def OnBtnRSHFIQ(self, event):
        print('OnBtnRSHFIQ() called back with event', event)
        lib_rshfiq.control_panel(self.hardware)

Config設定

ユーザー専用ファイルの設定パネルを下記に示します。

Quisk's user-specific file configuration panel.

手順は下記の通りです。

  1. *RS-HFIQ*タグを開く。
  2. Hardwareタグを開く。
  3. RS-HFIQハードウェアファイルのパスを設定する。
  4. 追加ボタン定義ファイルのパスを設定する。
  5. Quiskを再立ち上げすると、「RSHFIQ」ボタンが出現します。
  6. この時、スライダの長さはボタンパネル高さと一致するように伸長します。

RS-HFIQ内蔵テスト機能の実行

実装方法を変えたRS-HFIQ内蔵テスト機能の動作検証を行いました。

Execution result of RS-HFIQ built-in test function. (1) Test signal injected into USB side.
Execution result of RS-HFIQ built-in test function. (2) Test signal injection on LSB side.

上側がLO=7.020MHzに対して1kHzアップの7.021MHzのBIT信号をUSB側に注入した場合、下側が1kHzダウンの7.019MHzのBIT信号をLSB側に注入した場合を示します。
LSB側の信号がUSB側に漏れたイメージの方が若干大きいことがテストで再現できています。この結果はHDSDRによる測定結果と一致します。