IR202赤外線カメラのデータを取得

IR202 という携帯電話に接続する赤外線カメラを買ってみました。
解像度80x60とちゃんと画像として見られるレベルながら比較的安価です(最近円安のせいか値上がりしていますが…)。
PerfectPrime IR202 赤外線サーマルイメージャーカメラ (Android TypeC)

通常は対応する携帯のアプリを入れて使用します。
IR202 Thermal Camera Viewer - Google Play のアプリ
https://play-lh.googleusercontent.com/ovxdbSB7FARB0o621YUwia3-WEvh9elqrjbAuOWlIsV7XNUXl-96Ml2gA4FUCF5oXWe5=w5120-h2880

実は普段私はiPhoneを使っていますが、敢えてAndroid版を購入。USB Type-C接続なので、PCに繋いでデータが取れるんじゃないかと思ったからです。

さっそくPC (Linuxで試しましたが、MacWindowsでも同様に認識されます) に繋いで見ると、Virtual COMというデバイスとして見え、USBモデム(シリアルポート)として認識されました。

$ lsusb | grep COM
Bus 003 Device 021: ID 0416:b002 Winbond Electronics Corp. USB Virtual COM
$ dmesg | tail
[12151.951595] usb 3-1.4: new full-speed USB device number 21 using xhci_hcd
[12152.069983] usb 3-1.4: New USB device found, idVendor=0416, idProduct=b002, bcdDevice= 3.00
[12152.069989] usb 3-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[12152.069991] usb 3-1.4: Product: USB Virtual COM
[12152.069993] usb 3-1.4: Manufacturer: Nuvoton
[12152.109110] cdc_acm 3-1.4:1.0: ttyACM0: USB ACM device

データシートなどは見つけられなかったので、アプリの動作を調べてみました。起動時に初期化/データ送信開始コマンド、終了時にデータ送信停止コマンドを送っているようでした。
シリアルポートに 115200bps で接続し、下記コマンドを送ってやると、想定どおりデータを取得できました。
#[size (hex 4B)][command (4B)][data][CRC (hex 4B)] という構造をしているようです。デバイスからのデータも同様の形式でした。

内容 コマンド
初期化 #000CWREGB40402F3
データ送信開始 #000CWREGB10302DE
データ送信停止 #000CWREGB10002DB

バイスからのデータを眺めると、GFRA というcommandで、ヘッダらしきもの(詳細不明)の後に80×62のピクセル値(little endian 16bit)が続くという形式でした。仕様よりも実際は2行多いようです。
これを温度に変換したいのですが、変換規則を調べるためにカップウォーマーとか保冷剤とかいろんな温度の物を撮ってアプリの結果と比べるという方法で対応を調べました。1次関数で大丈夫そうです。ただ、他の放射温度系と較べてみると、アプリの出力は高温は高く、低温は低く表示されがちでした。対象物との距離にも多少影響されます。あくまで周囲との高低を見る程度にして温度はあまり厳密でないと思ったほうが良さそうですね。

IR202 Graph

あとはこれを画像化してやればOK。Rubyでデータを取得してWebSocketで送りJavaScriptCanvasに描画してみました。
生データだと結構なノイズが乗るので、適当にフィルタを噛ましています(何か色々やってますがなるべく応答速度を犠牲にしすぎずにノイズを減らそうとした結果です)。
コードはこちら。

クリックした位置の温度、最高/最低温度およびその場所が表示されます。
下のスクリーンショットで青くなっているのはエアコンの吹き出し口です。

PCでデータ処理できるようになったので、温度監視とか動きの認識とかに応用できそうですね。

Arduino MKR WAN 1310に搭載されたECC508を利用して乱数を生成してみる

Arduino MKR WAN 1310にはECC508というセキュアエレメントが搭載されており、これを用いて公開鍵認証などを安全に実現することができます。
ハードウェア乱数生成器を搭載しているため、暗号論的にセキュアな乱数を生成することもできます。

以前の記事で紹介したLoRa GPSノードでは公開鍵認証は利用しませんでしたが、共通鍵暗号のIVの初期化にこのチップを利用しているため、利用方法を書いておきます。

まず、ArduinoECCX08 ライブラリをライブラリマネージャで導入します。
f:id:NeoCat:20220412035243p:plain:w600

するとスケッチ例 > ArduinoECCX08 以下に幾つかのサンプルが追加されます。

このうちECCX08RandomNumberがまさに乱数生成をするサンプルなのですが、これを利用する前に lock という作業が必要です。これは設定をチップに書き込んで二度と改変できないようにする操作です。以下ではデフォルト設定 ECCX08_DEFAULT_TLS_CONFIG を利用するので、特定の用途で使う予定がある場合はそれを使う必要があるかもしれません。

スケッチ例の Tools > ECCX08CSR を書き込み、シリアルコンソールをつなぎます。

すると購入したばかりのMKRであれば、

The ECCX08 on your board is not locked, would you like to PERMANENTLY configure and lock it now? (y/N)

と聞かれますので、 y を入力すると、チップに初期設定が書き込まれます。

それ以降の操作はここでは不要です。

改めて ECCX08RandomNumber を書き込んでやると、乱数値がシリアル出力されるはずです。

最小では

// setup
ECCX08.begin();
if (!ECCX08.locked()) { error(...) }

long random = ECCX08.random(65535);

などと指定すれば乱数値が得られます。
なおlockせずに利用しようとするとRNGがテスト用に常に特定パターンを返すため、lockされていない場合はエラーにしてこの値を使用してはいけません。

他に以下のような乱数を取得するための関数が用意されています。

  long random(long max);
  long random(long min, long max);
  int random(byte data[], size_t length);

LoRaの通信波形をSDRで見てみた

前の記事で作成したGPSノードの通信の波形を、SDR (Software Defined Radio)で捉えて可視化してみました。
neocat.hatenablog.com


SDRの受信にはRTL2832Uなどのチップを積んだ安価なUSB TVチューナーなどが使えます。

が、今回は HackRF One を使用しました。
HackRF One + Portapack H2

受信ソフトウェアはMacで簡単に使える gqrx を使います。

まずインストールは Homebrew

brew install gqrx

でOK。アプリケーションフォルダに通常のアプリケーションとしてインストールされます。HackRF One を接続した状態で起動すると、デバイスにHackRF Oneが現れるので、選択して起動します。キャプチャのサンプルレートが選べますが、16000000 (16MHz) にしておきました。

起動したら、今回使用した周波数である923MHzを入力してチューニングします。下図ではピッタリに合わせていますが、このままだと真ん中に強いピークが出てしまうので、右のReceiver Optionsの方に1000 kHzくらいを入力してハードウェア周波数を922MHzなどにずらした方が良さそうです。

この状態で通信をすると、上図のようにFFTのところに赤いピークが現れます。が、このままだと荒すぎて波形は見れません。そこで、データを書き出して別のソフトで可視化を行なってみます。
メニューから Tools > I/Q recorder を開き、適当なディレクトリを指定して、通信の直前に Rec を押し、通信後に止めます。これで生データがファイル出力されます。数秒の Rec で数100MBから1GB程度のファイルが出力されるので注意してください。

可視化には inspectrum を使います。同じく brew でインストールし、コマンドラインから起動します。

brew install inspectrum
inspectrum

ウィンドウが開くので、 Sample rate を今回使用した 16000000 を入力し、 Open file で gqrx で出力したファイルを指定します。
すると、巨大な画像が表示されますので、横軸(秒)と周波数(今回だと 1000 kHz ずらして撮っているのでその付近)を参考に、スクロールしていくと、波形が見つかるはずです。Zoomや色付けするPowerを調整してやると、こんな感じでLoRaの通信波形が描画できました。

LoRaの通信波形

左側がGPSノードからのデータ送信、右側がゲートウェイからのACK送信です。(ゲートウェイの至近でキャプチャしたため、ゲートウェイ側の信号が強くて描画が荒れてしまっていますが…)

LoRa変調ではCSS(Chirp Spread Spectrum)、チャープスペクトラム拡散と呼ばれる方式を利用しています。使う帯域(今回は125kHz)分の周波数にわたって低い方から高い方に連続的に周波数をスイープさせているのが見てとれますね。これにより途中でノイズや受信できない周波数などがあっても影響を受けにくくなっています。
ノードからの送信では、最初に最低→最高までのスイープの繰り返しが10回あり、最高→最低に反転して2回繰り返しています。1つの繰り返しが1つのシンボルになります。ここまでの部分はプリアンプルで、受信側と同期を取るためにあります。
そこから先に少し複雑なパターンが現れますが、これはデータの数ビット分に応じて、シンボルのスイープの開始位置をずらすという符号化を行なっているものです。
例えば2bit、4通りの値を1シンボルで送るとすると、以下の4つのいずれかを送ることで 0, 1, 2, 3を表すことになります。
(Signals 2022より引用)

前の記事で SF によって送信速度/感度を調整できると書きましたが、この SF が1シンボルで送るbit数に相当します。SF=10であれば、1024通りのパターンを送るということになります。加えて、SFが1増えるごとに、1シンボルにかける時間を2倍にします。後者の方が通信時間に対する影響が大きいため、SFが1上がると概ねビットレートは半分ということになります*1。ゆっくり送信した場合の方が情報あたりの合計電力が上がりノイズ耐性が改善しますので、SFを上げることで通信距離が広げられるというわけですね。

ゲートウェイからの送信時は、スイープの方向が逆転しています。これはスケッチ中にあった

  LoRa.enableInvertIQ();                // active invert I and Q signals

という指定の効果で、ノードはゲートウェイからの通信のみを受信、ゲートウェイはノードからの通信のみを受信するために区別をつけるための機能です。

*1:例えばSF 9→10の場合、同一のデータ部分の送信にかかる時間は単純計算で 2*9/10 = 1.8倍 になります。プリアンプルなどデータの乗らない部分はそのまま2倍長くなるのでさらに2倍に近づきます。

GPSの現在位置をLoRaで送信して距離を測ってみた (Arduino MKR WAN 1310)

TL;DR

LoRa は最大数kmの長距離でセンサデータ等の通信ができるとされている通信方式です。
実際にGPSで取得した現在位置を送信するノードをArduino MKR WAN 1310を使って作成し、都市部(東京23区内)でこれを持ち歩いた時にどのくらいの距離まで通信できるのかを調べてみました。
通信距離はアンテナ設置状況で大きく変わるものです。今回はビルの窓にアンテナを貼り付けた程度の非常に簡易的なセットアップでしたが、それでも800m程度離れた場所でもデータを送信できることを確認できました。
f:id:NeoCat:20220409173351j:plain

LoRa / LoRaWANについて

LoRaは、LPWA(低消費電力・長距離)通信のための方式の1つです。日本では免許不要の920〜928MHz帯を利用して、バッテリーで長時間、センサデータ等の小さいデータを都市部で数km(開けた場所なら数十kmというデータも)の範囲で送信することができるとされています。
LoRaWANという単語の方が有名かもしれませんが、これはLoRaを利用して相互にデータを交換するためのプロトコル(L2)までを規定したものです。LoRaWANを利用した通信網を提供する商用サービスや、コミュニティで運営されているThe Things Network (TTN)もあります。他方、自分のデバイスゲートウェイ間で通信するだけであれば、LoRaWANを用いずに任意のプロトコルで通信することもでき、これはプライベートLoRaと呼ばれます。

参考解説記事: いまさら聞けないLoRaWAN入門:産業用ネットワーク技術解説(1/4 ページ) - MONOist


現実的に都市部でどれくらいの範囲で通信できるのかに興味があったため、GPSの現在位置をLoRaで送信するデバイスを作って試してみることにしました。
実験した場所は残念ながらTTNの圏外だったこともあり、今回はプライベートLoRaを利用しています。

LoRaの通信速度

続きを読む

USB Type-Cケーブルで接続すると動作しないQiワイヤレス充電器の謎を調べてみた

古めのUSB Type-C接続のデバイスの中には、なぜかUSB Type-C ⇔ Type-Cケーブルを使って電源に接続すると動作しないものがあります。


具体的には、リリース直後のM5StickCは、Type-C ⇔ Type-CケーブルでMacに接続すると動作しない問題がありました。
これは現在は改善されており、裏面のブロックダイアグラムに、「RTC」が記載されているロットでは正常に動作します。

他にも、2018年頃に買ったTronsmartのQiワイヤレス充電器(もう入手できない模様)はType-Cコネクタがついているのですが、同じくType-CコネクタのついたACアダプタにType-Cケーブルで接続すると電源が入りませんでした。

どちらも回避方法があり、USB Type-A ⇔ Type-C や Micro-B ケーブルにType-C変換アダプタをつけて接続してやるとなぜか動作します。

f:id:NeoCat:20220108182702j:plain f:id:NeoCat:20220108182714j:plain
USB Type-Cケーブル USB Type-A / Micro-Bケーブル + Type-Cアダプタ*2
動作しない 動作する

一体何が違うのか、USBケーブルチェッカーを使って調べてみました。
BitTradeOne ADUSBCIM USB CABLE CHECKER 2

USBケーブルチェッカーで調べてみた

まずはUSB Type-Cケーブルの方から。

一方USB Type-A ⇔ Micro-Bケーブルの両端にType-Cアダプタをつけてみた場合はこちら。

CCが接続されていることを示すLEDが消灯し、代わりにディスプレイにA側のCCが5.1kΩでプルダウンされ、B側のCCが56kΩでプルアップされていることが表示されています。
(CC1, CC2は上下の違いなので、上下逆に差し込めば逆になります。)

これは変換アダプタに内蔵された抵抗によるものなので、ケーブルなしでアダプタのみチェッカーに接続しても表示されます。

CCピンは、接続を検出したり、USB PD (Power Delivery)や映像伝送などで使われるAlt Modeへの切り替えをネゴシエーションするための通信線です。充電器や単純な機器の場合は抵抗でプルアップ・プルダウンすることで対応することもできます。

A側の5.1kΩプルダウンは、接続の向きを示すために入っているものです。USB Type-Cには上下それぞれにUSB 2.0のD+/D-信号線があるので、この抵抗を使って接続された向きを識別してどちら側を使うかが選択されます。


B側の56kΩプルアップは、給電能力を示すために入っています。表を見ると56kΩはUSB Default Powerで、この場合はUSB2.0接続なので0.5A(3.0なら0.9A)ということになります。


さて、これで違いはCCピンの処理にあることがわかりました。Type-Cケーブルで接続するとうまく動作しない機器は、電源やPCとCCピン同士が接続されてしまうと、通信によるネゴシエーションに失敗してしまってうまく接続できないのだろうと考えられます。アダプタを挟むとCCピン同士が接続されないので、失敗を回避できていたということです。

おまけで別のケーブルのチェック

Macの充電ケーブル。大電流が流せることを示すeMarkerが入ったUSB2.0ですね。

別のType-Cケーブルです。これも充電器は動作しない。USB3.0に対応しているのでTX/RX-1が配線されている。TX/RX-2やサブバンドは繋がっていないのでAlt Modeの映像出力やUSB3.1 Gen1x2などは利用できない。

Full Featuredなケーブルなら全部のLEDがつくはずだけど意外となかった…。

電源をUSB PDトリガー調べてみた

ついでなので、USB Type-C電源の方も、PD検出機能付きのチェッカーで調べてみました。

TC66C Type-C Bluetooth PDトリガーUSB電圧電流計容量計

TC66Cは双方向対応の電圧・電流チェッカーの機能のほか、安価ながらも、電源が対応しているプロトコルを検出したり、それを使って各種電圧を出力させるトリガー機能を持っています(QC, USB-PDの他, SamsungHuaweiのベンダ独自規格に対応。検出時はいろんな電圧が出力されてしまうので絶対に他のデバイスを接続しないようにしましょう)。

対応プロトコルと出力電圧・電流を調べたり(非対応は赤色)、

実際に選択した電圧を出力させたり(この写真だと20V出ていることが確認できます)、

QC3.0を使って0.2V単位で出力電圧を操作できたりします。


ところで、調べているうちに、このチェッカーを通して件のワイヤレス充電器を繋ぐと、どういうわけだかUSB Type-Cケーブルでもちゃんと電源が入って使えることが判明しました。あれれ? ただの電圧・電流チェックモードなので、何かのプロトコルをトリガーしている訳ではありません。それどころか、ちゃんとPDでネゴシエーションが成立して9Vを引き出せている模様*1

何かのインピーダンス整合だか電源ONタイミングだかの不具合が、このチェッカーのCCピン接続のおかげで解消したのでしょうか?
ということで、思わぬところでチェッカーが役に立つことが判明しました(笑)

*1:確かに裏面に9V入力対応と書いてあるけど、今までのアダプタ経由ではCCピンが繋がっていなかったので成功していなかった

M5Paperの動作中の消費電力を削減する

M5Paper を動作させっぱなしにすると残像が残る?

M5Paper は、静電容量タッチスクリーン付きの 540 x 960 の4.7インチ電子ペーパー(EPD)を備えた、ESP32搭載のデバイスです。
無線LANやBT通信などと組み合わせて、色々なモノを作ることができます。*1



1150 mAhのLipoバッテリーを持っているため、これと電子ペーパーの電源を落としても表示が消えない特性を生かして、長期間ディープスリープさせながら定期的に画像取得するような作例がよく見られます。
しかし、タッチセンサーを利用した動作をする場合、タッチ状態を監視して反応(画面を再描画したり通信したり)したいため、内部状態がリセットされてしまうディープスリープは使えず、USB電源等に繋いで常時稼働させる必要があります。


さて、M5Paperでタッチ操作が可能なスケジューラを作り、常時通電で稼働させていたのですが、時計を1分に1度更新していたところ、画面のUSB-Cポート側の端にだけ、白黒反転した残像のようなものが残るようになってきました。
※配線の都合上、上下反対(つまりUSB-Cポートの位置が上になるよう)にして使っています。
f:id:NeoCat:20210725112051j:plain:w400
最初は電子ペーパーの劣化かと思ったのですが、電源を落としてしばらく放置すると何事もなかったように元に戻ります。
そして、残像の残るあたりをタッチすると、なんだか暖かいことに気がつきました。
どうやらこの高温が残像の原因らしく、電源を落として冷ますと元に戻っていたようです。
温度を測ってみるとこんなかんじでした。ピンポイントで測ると40℃くらいになっています。。
f:id:NeoCat:20210725133040p:plain:w400

そういえば、ESP32は最大消費電力が大きいので発熱もそれなりにあり、常時稼働させていると気温センサ等で正しい値がとれなくなったりします。
というわけで、消費電力を抑えることを考えてみることにしました。

M5Paper稼働中の電流計測

まずは簡単にM5Paperの稼働中にどれくらいの電流が流れているか計測してみました。
フル充電後にUSB電源で動作させてUSBチェッカーで1秒ごとに計測した値なので、ピーク値ではなくラフな平均的な電流値です。

状態電流値
WiFi通信中180 - 200mA
WiFi待機中150 mA

WiFi待機中」は、WiFiアクセスポイントへの接続はしたまま通信はせずにloop()をぐるぐる回っている状態です。
普通のESP32と比べても大きい値となっています。
調べてみたところ、電子ペーパー用のコントローラ IT8951 (裏面にも描いてあります) が60-80msくらい電流を使っているようで、この分大きいということでした。

IT8951 の動作電流を抑える

EPD周りの電源は、まとめて以下の関数で落とすことができるようになっています。

M5.disableEPDPower()

しかしこれをやってしまうと、電源を再投入しても描画がノイズだらけになったり掠れたりしてしまい、リセットしない限り正常に復帰できないようです。
ディープスリープする場合は復帰時はどのみちリセットになるので構いませんが、タッチ操作に応答して画面を部分書き換えしたい場合にはリセットされては困ります。

IT8951 のデータシートを読んでみると、IT8951 には電源モードとして Active / StandBy / Sleep の3つがあり、StandBy / Sleep では一部の機能を抑止して消費電力を抑えられるとあります。
これを使うにはSPI等でコマンドを送る必要があるため、M5PaperのArduino用ライブラリに関数を足して、電源モードを切り替えられるようにしました。
Pull Request を送ってみました。)
これを使って待機中にはIT8951をSleepに入れてやり、再描画が必要になったらActiveに戻すようにしてやると、見事に60mA程度の電流をカットすることができました。
(StandByでも同じくらい電流が減ります。細かい違いは今回は測定できませんでした)

  M5.EPD.Sleep();
  // ... タッチ操作を待機する ...
  M5.EPD.Active();
  // ... タッチ操作に反応して再描画 ...

ESP32のライトスリープとの組み合わせ

残りの消費電力の削減はESP32のライトスリープによって行います。
まず、通信しない時はWiFiをOFFにしてしまいます。

  delay(1000); // 通信完了直後に OFF にしてしまうとコネクション切断処理が途中のまま残ってしまうため少し待機
  WiFi.mode(WIFI_OFF); // または   WiFi.disconnect(true);

再度通信する際は WiFi.mode(WIFI_STA); WiFi.begin(...) で再接続が必要なため、少し時間がかかります(固定IPアドレスにするといくらか時間を短縮できます)。


その上で、待機中に ESP32 をライトスリープに入れます。
ライトスリープなら、ディープスリープと違ってメモリ内容は維持され、復帰時もスリープに入ったところから処理が再開されるので、簡単に使えます*2

ライトスリープはタイマーやGPIO、UPCなど、様々な復帰要因に対応しています。
(→ 参考: ESP32のライトスリープを調べる | Lang-ship
今回は時計の画面更新のため、およびタッチスクリーン操作で復帰させたいので、以下のようにしました。

void loop() {
...
    Serial.flush();  // Serialをflushさせておく
    esp_sleep_enable_timer_wakeup(500000);  // 0.5s後に起床
    esp_sleep_enable_ext0_wakeup(GPIO_NUM_36, LOW);  // タッチで GPIO36 が LOW になるのでこの時も起床
    esp_light_sleep_start();  // ライトスリープ開始

    // 起床後の処理
}

ほとんど delay() を入れるくらいの感覚で使えますね。

改善後の動作電流

さて、これらの対応でどのくらい動作電流は変わったか計測してみました。

状態電流値
WiFi通信中180 - 200mA
WiFi OFF時120 - 140mA
IT8951 Sleep時60mA
Light Sleep時? - 20mA

WiFi OFF + IT8951 Sleep + Light Sleep時には最低値で1桁mA程度まで減少させることができました(精度不足で細かい値は取れず)。
0.5s 毎の起床時と平均すると10mA前後といったところでしょうか。
元と比べると平均消費電力は10分の1程度に大きく節減でき、バッテリー動作でも1日以上は動作する計算になります。

発熱も大きく抑えられ、残像が出る問題も解決することができました。
f:id:NeoCat:20210725133105p:plain:w400


かなりの効果もあったことだし、Pull Request 取り込まれるといいなあ。

*1:v1.1が出ましたが、この記事はv1.0を元に書いています。基本的に同スペックなのでv1.1でも通用するでしょう。

*2:ただしメインCPUはpause状態となり処理が止まってしまうので、WiFiなど定期的な維持処理が必要な機能は切っておく必要があります.

Macのスリープが時々勝手に解除されるのを防ぐ

Macのスリープが時々勝手に解除されている?

前の記事でUSBファンを繋いだのですが、Macのスリープが数時間に1回、勝手に解除されてはまたスリープするという動作をしているらしく、時々ファン音がするのが気になるようになりました。ファン以外でも、USB HDDなどを繋いでいる場合も、勝手にスピンアップし始めて気になるというケースがままあるようです。

システム環境設定 > バッテリーで PowerNap を切ったりしたのですがそれだけでは改善せず。

この原因を調べてみました。なおOSバージョンはBig Surです。

調べ方は、 log show --last 10000 --style syslog | fgrep "Wake reason" で出てくる、以下のような行を見るというものです。調べてみると、さまざまな理由で起動してきている様子。

log show --last 10000 --style syslog | fgrep "Wake reason"
...
2021-07-11 07:51:29.506171+0900  localhost kernel[0]: (AppleACPIPlatform) AppleACPIPlatformPower Wake reason: EC.RTC (Alarm)
...
Wake reason = ARPT (Network)

無線LANを契機にスリープが解除されたときに出ます。
色々と対応方法はあるようですが、

sudo pmset -a tcpkeepalive 0

を実行してやるというのが有効なようです。(実行すると「スリープ中にFind My Macがうまく動かなくなるかもよ」と言ったメッセージが出ますが、どのみち移動してしまったらネットワーク接続できないので位置のレポートはできませんし、気にせず切ってしまいます。)

なお pmset は他にもスリープの動作に関して様々な設定ができるコマンドです。( 参考: man pmset , pmset で Mac の電源制御 - Qiita )

Wake reason = EC.RTC (Alarm)

タイマーで予約された起動です。
システム環境設定のバッテリー > スケジュールで予約されているもののほか、システムが勝手に予約していることもあります。
以下のファイルを見ると、どのプロセスがいつ起動を予約しているかを見ることができます。

/Library/Preferences/SystemConfiguration/com.apple.AutoWake.plist

今回の場合、「スクリーンタイム」が使用状況をレポートするためのエントリが2時間おきくらいに起動するよう設定しているのが見つかりました。
いちいちスリープ解除する必要なんてなさそうに思いますが、他の同一iCloudアカウントのデバイスとレポートを共有できるようなので、そのためなのでしょうか??
特に不要なので、システム環境設定 > スクリーンタイム > オプション で「オフにする」を実行します。
これだけではすぐに予約が解除されなかったため、上記のファイルを一度削除してから、バッテリー > スケジュール で予約を適当に ON→OFF と操作してファイルを再作成させ、予約が空になったことを確認します。

sudo rm /Library/Preferences/SystemConfiguration/com.apple.AutoWake.plist  # 一度削除


私の場合は上記で勝手に起動してくるのは収まって、静かになりました。バッテリーの持ち具合なんかにも影響しそうな気がします。