何度か断片で記事にしましたが、その後使ってみて、バグつぶしとか、機能追加があったので、今回は、まとめを書いておきます。
まずは、きっかけとして、2つの動機が重なり、SINADインディケータを試作しました。 そもそもは、自作受信機の感度が今一つなので、感度評価しようとしたのが始まりです。tinySAにSG機能が付いており、受信側にはSINAD計が欲しいなと思った次第です。使い勝手よさそうなのはメータ式のSINAD計で、測定時にメータを合わせるスタイルです。回路をコピペしてDIYするなら、いっそのことデジタル化OLED表示にするかと思いつきました。JH1LHVさんが、M5Stackで試作されたのを見たのもちょうどきっかけになりました。どうもありがとうございます。
それと、もう一つの動機がちょうど入手したESP32-C3 dev kit super miniの活用です。Arduino互換で動作し、切手サイズ、しかも安価。このマイコンでDIY測定器グッズが何かできないか、という思い付きです。 この2つの動機が重なり、ESP32-C3を使うSINAD/THDインディケータの試作を開始しました。
手掛けた時点でESP32-C3のADCの評判がいまいちでした。くせがあり、ノイズ影響を受け、低レベル領域ではリニアニティが悪いなどのコメントがありました。でもちょっとした試作回路なら我慢できるかと割り切り手掛けました。本気でやるならI2SのADC,DACでやらないといけませんよね。
実装概要 ハードウェアは至ってシンプルで、ESP32-C3にOLED(SSD1306, 128×64)とロータリーエンコーダを組み合わせた構成。従来から手掛けているR909受信機とかVFO用のパネル制御部分と互換にしました。これに音声入力はESP32-C3内蔵ADCにDCバイアスだけ付け直結するという、簡易式にしました。

ソフトウェアの核心は3つのブロックで構成します。 IIRノッチフィルタ(SINAD用) 1kHz中心、Q=20のIIRノッチフィルタでキャリア成分を除去します。入力RMSとノッチ後RMSの比からSINADを算出するのが基本的な数式処理です
SINAD(dB) = 20×log10(vInRMS / vNotchRMS)
入力信号確認のためのFFT表示 10kHzサンプリング、512点バーストサンプリングによるFFT表示。
0〜4kHz(bin1〜bin205)を128ピクセルにマッピングする。
1k/2k/3k/4kHzのラベル付き。
THD計算(1kHz固定で信号歪率) FFTから基本波(bin51:1kHz)と高調波(bin102:2kHz、bin154:3kHz、bin205:4kHz)を抽出してTHD%を算出します。
THD(%) = √(f2²+f3²+f4²) / f1 × 100
displayModeはロータリーエンコーダで切り替え、7画面を持つ。 0:SINAD 1:WAVE_in 2:WAVE_notched 3:FFT_in 4:FFT_notched 5:PARAM 6:THD DDS(1kHz基準信号発生)もPWMで内蔵し、スイッチでON/OFFするようにした。

以上の仕様でDIYしました。一度はうまくいったと思ったんですが、改良したり機能アップしたりいじっていると、いくつかの問題点に行き当たりました。
伏兵その1:ISR干渉
始め無知なままロータリーエンコーダ用のライブラリrotary.hをそのまま使っていたが、どうもおかしいなと思ったら、ESP32-C3ではesp32用の関数でないとダメとのこと。AiEsp32RotaryEncoder.hを使ってみたました。でも、ダメ。
最初の難敵はISR(割り込みサービスルーチン)の干渉です。 ロータリーエンコーダのライブラリがISRを使用しており、DDS用のTickerと競合してADCサンプリングがストールした。さらにESP32-C3のUSB-CDC(GPIO2/3)も絡み、シリアルデバッグでデバッグモニターしようとしたら、かえってストールし、難航した。
GPIO2,3をロータリーエンコーダに使ってはSerialがダメなんです。
解決策は「全部ポーリングにする」という割り切りでした。 ロータリーエンコーダ:GPIO直接ポーリング プッシュスイッチ:エッジ検出ポーリング(200msデバウンス) 応答性は落ち、ロータリーエンコーダはゆっくり回すことになったが、ADCサンプリングの安定性が確保できた。
伏兵その2:ADCノイズという本命 ISR問題を解決した後、スマートフォンの信号発生アプリで1kHz正弦波を入力してSINADを測定しました。 結果は色々と対策してもせいぜい16〜24dBです。 スマートフォンの音声出力品質を考えれば50dB以上出るはず。何かがおかしい。 原因究明を進めた結果、以下の構造が判明した。
入力端子でのノイズ:ほぼゼロ(波形で確認) ADC出力のノイズ:60mV相当 入力端子にはノイズがないのに、ADC出力にはある。
これはESP32-C3内部のSAR-ADCの特性でしょう。サンプルホールド容量は数pF程度で非常に高インピーダンス。CPUクロック(160MHz)やDC-DCコンバータのスイッチングノイズが基板GNDを介して直接結合しているようだ。外部からは見えないが、ADCデジタル出力に現れてしまう。
加えて、デバッグ用に入れていたADC_LOOP_MONITOR(GPIO7でサンプリング毎にHIGH/LOWトグル→10kHz矩形波発生)もノイズ源になっていたようだ。これも除去した。
ESP32-C3 ADCの現実的なSINAD上限:
vInRMS 0.46V / vNotchRMS 0.04V = 20×log10(11.5) ≈ 21dB
ソフトウェアでできることはやり尽くした。これがESP32-C3単体で使う場合の実力値なんでしょうね。 測定系モニターで使う際の誤差として重要なのは、この限界を「仕様」として把握、割り切ることですね。
ESP32-C3 SINAD/THDインディケータの測定誤差:
SINAD:実力値フロア約20dB(真値がそれ以上でもノイズで飽和してしまう)
THD :ADCコンタミにより約1%が加算誤差として合算される この誤差を割り切れば、12dB SINADの合否判定にはなんとか余裕があり、受信機の感度測定用インディケータとしては実用上の目安となるでしょう。 ということで、その2に続く。














