2026年6月6日土曜日

プログラマブルシンクモジュール(1)



電源から決めた電流をひっぱるモジュールを作りたい。電源回路や電池の評価に使う。

世の中には電子負荷とか充放電試験装置とかあるにはあるんだけど、プログラム可能なステップ数やサンプリングレートが限られてたり、制御範囲が所望の範囲じゃなかったりってことで、こういう場合は自分で作ってしまおう。ちな、成功する保証はない。

目次
  1. 仕様
  2. 方針
  3. 回路設計

  1. 仕様    
  2. 仕様ってほどでもないけど、
    • シンク回路
      • 電源 : USB
      • 制御範囲 : 0uA~100uA
      • ステップ数 : できるだけたくさん
      • サンプリングレート : できるだけ早め(~250kS/s)
    • モニター回路(電圧の変動をモニター)
      • 電源 : USB
      • 計測範囲 : 0V~4.2V
      • サンプリングレート : 250kS/s
    (目次)

  3. 方針    
    • シンク回路
    • オペアンプによる定電流回路をベースにして、VrefをDACで制御する。DACのrefはマルチプレクサで選択できるようにして、広い範囲で細かく調整できるようにする。<--これがミソってか工夫したところ。
      能書きはこれくらいで、ズバリこんな感じ。
      ちなみに、ここに出てくる抵抗は高精度じゃないといけなくて、出力段のオペアンプは超低オフセットじゃないといけない。
    • モニター回路
    • ボルテージフォロアで受けて、分圧して、マイコンのADCで測定するっていう簡単なものにします。こんな感じ。

    (目次)

  4. 回路設計    
    • シンク回路
      • DACのREFに入れる電圧の精度
      • 高精度な基準電圧源を高精度な抵抗で分圧する、、、+/-0.1%, 15ppm/deg.C
      • 出力段のオペアンプのオフセット
      • これが冴えないと、0Aにしたいときに0Aにできない
        まあ、オフセットができるだけ小さいものを選ぶ
      • 検出抵抗の精度と安定度
      • ここで安定して狙った電流になるかどうかが決まる、、、+/-0.1%, 15ppm/deg.C
      • ノイズをできるだけ抑える
      • 制御電圧にノイズが乗ってしまうともう何やってるかわからなくなる、、、どんだけ電源をきれいにできるかが課題、、、フェライトビーズを使いつつデカップリングコンデンサをふんだんに入れる
        で、こうなる
        ラダー抵抗は2,18,180,1800ohmになっていて、REF3020の出力2.048Vを2.048V, 204.8mV, 20.48mV, 2.048mVとして出力して、MCP6004がボルテージフォロアとして電圧をコピーして、TMUX1004で選択して、MCP4921で4096分割する。なので、LSBは500uV, 50uV, 5uV, 0.5uVとめっちゃ細かく刻めるってもくろみ。そうすることで、
        I_max[uA] LSB[uA]
        102400 25
        10240 2.5
        1024 0.25
        102.4 0.025
        って感じで制御できるはず。まあ、オペアンプの精度にかかってますけど、、、
        制御内容は大したことないので、マイコンは5V系でSPIが高速でパタンをたくさん覚えられる(Flash容量が大きめの)AVR128DB28を選択。
    • モニター回路
      • ボルテージフォロアで電圧をコピーしてから分圧する
      • ボルテージフォロアで受けることで評価対象からシンク回路以外に電流が流れることを防止する
      • ADCはマイコン内蔵
      • 単体のADCは高い!むしろそれなりのマイコンを使った方がいろいろラクできる、、、いずれにしても高速に計測した大量のデータを一時的に高速に保存するために外付けのSRAMが必要
        で、こうなる。
        AD変換した結果を高速にSRAMに放り込みたいので、マイコンはATSAMD21E18Aを選択。
    • AW
    • こんなかんじにしてみた
      、、、結構ぴっちぴち;
    (目次)


つづく


現代の暴君、、、ってか現在は暴君の時代なのかも(๑╯ﻌ╰๑)

2026年5月5日火曜日

XIAO nRF54L15



Seeed Studio XIAO nRF54L15が届いたのでまずは使ってみる。ちな、2個購入(・∀・; )。秋月で1個1800円。まあ高いものではない。
実は連休前に届いていて、連休中のおもちゃとして遊ぶ予定だったけど、測距でこねくり回しが過ぎてnRF54に手が回らなかった、、、ただいま測距のキャリブレーションで壁にぶち当たっているので気分転換にnRF54を使ってみる。nRF54はChannelSounding公式対応デバイスなので、それが一体どういうことなのかもわかるとうれしい。
ところで、参考サイトは、こちら(Seeed Studio XIAO nRF54L15(Sense) 入門ガイド)。詳しく書いてあるみたいなので、ここで説明する必要はない^^;このXIAO nRF54L15はなんと、nRF54L15だけでなくSAMD11D14Aも実装されていて、SAMD11がCMSIS-DAPになってくれているので、ライターを準備しなくてもOpenOCDで書き込みもデバッグできるっていうすぐれもの。こんなめっちゃ小さいのに(。゚ω゚) 。環境の準備は参考サイトに従ってやるんだけど、まあうちの場合はnRF Connect SDKの設定は終わっているので、「XIAO nRF54L15 ボードの追加」ってところをやればいいはず。、、、なんだけど、やらんでいいらしい。現時点で最新のsdk v3.2.4にはXIAO nRF54L15のボード定義がすでに組み込まれているから、やらんでいいと言うか、むしろしてはいけないらしい(Gemini談)。
で、PCとの接続ってSAMD11のCMSIS-DAPだけなのでUARTどうしたらいいの?ってことでGeminiに聞いたら、回路図でnRF54L15のTX/RXピンがSAMD11につながっていればSAMD11のUSB-CDCクラスを介してPCに接続できるはず、、、ってことで回路図見たら確かに接続されている。んで、XIAOのボード定義を使用すれば、普通にUART出力できるって。だまされたと思ってやってみる。
Create a new application
Copy a sample
SDK=v3.2.4
Helloと入力して"Hello world"を探す
いい感じのフォルダを指定して"Enter"キーを押す
まあ、安全のためNew windowで開く
↓こんなん出るけど無視
Add build configuration
"Nordic SoC"ラジオボタンを選ばないとxiaoが出ない;
"xiao_nrf54l15/nrf54l15/cpuapp"を選んで(これでいいのかわからんけど)下の方にスクロールして"Generate and Build"
で、エラーとか出なかったのできっとビルドに成功しているはず。
で、書き込みは、、、
"Manage toolchains"を押して、Open terminal profile
こういうのが出る
"west flash"ってコマンドを入れるとこうなる
きっとうまくいっているに違いない、、、💦
VSCodeのシリアルモニターを使って、それらしいポートを開いてみる、、、この段階では何も出ない💦
ボード上のリセットボタンを押してみる
こうなる
うまくいったんやないか、、、簡単すぎる、、、ていうかお膳立てが良くできてる💦


明日から本業がんばる。まずは仁義なきイス取りゲームをがんばる٩( 'ω' )و

2026年5月1日金曜日

nRF52833で測距(7) - IQデータの処理方法(4)



ちょっと本気出して測距を考えてみたい。IQデータの料理方法についてまとめておきたい。、、、の第4回目。MUSICやる。(タイトルにnRF52833ってもう要らんなー、、、が、今さら消すわけにもいかない)

CaponまでやったらMUSICもやってみる(<--Geminiのアドバイスによる(´ㅂ`; ))。で、例によってMUSICとはどういうものかGeminiに解説してもらったのでこちらをどうぞσ( ̄∇ ̄; )。ちな、Geminiが結論のところに書いてくれるとよかったんだけど、MUSICスペクトルは信号そのものの強さではなく数学的な直交性(離れ具合)がプロットされているので、MUSICスペクトラムの「ピークの高さ」と「信号の電力(強さ)」には直接的な相関関係は無いです。(しかし、これ考えた人ほんとすごいね、発想が。どういう思考経路でここに至るのか見当もつかん。)
で、MUSICスペクトラムは
\[ P_{\text{MU}}(t) = \frac{\mathbf{a}^H(t) \mathbf{a}(t)}{\mathbf{a}^H(t) \mathbf{E}_n \mathbf{E}_n^H \mathbf{a}(t)} \tag{1} \] ってなっていて、$\mathbf{R}_{xx}$の固有値分解がこうなっていて、
\[ \mathbf{R}_{xx} = \mathbf{U} \mathbf{\Lambda} \mathbf{U}^H = \sum_{m=0}^{M-1} \lambda_m \mathbf{e}_m \mathbf{e}_m^H \tag{2} \] (添え字を0始まりに変更)
で、$M$個の固有値$\lambda_m$を昇順に並べたときに、どっかからどっかまでが信号で、どっかからどっかまでがノイズって(ある意味勝手に)決める。で、ノイズに該当するとした固有ベクトルを連結して$\mathbf{E}_n$とするわけだ
\[ \mathbf{E}_n = (\mathbf{e}_{0}, \mathbf{e}_{1}, \dots, \mathbf{e}_{M-1-K}) \tag{3} \] 、、、numpyで固有値計算すると、がっちゃんこなって固有ベクトルが(行列で)出てくるから連結するというよりは取り出すってかんじになる。
で、$a(t)$はCaponのときと同じステアリングベクトル
\[ \mathbf{a}(t) = \begin{pmatrix} 1 \\ e^{-j 2 \pi \Delta f t} \\ \vdots \\ e^{-j 2 \pi (N-1)\Delta f t} \end{pmatrix} \tag{4} \]
いちおうこれでMUSICスペクトラムが計算できるのでやってみる。
ble_music.py

結果はこうなる

たしかにMUSICってよさそうに見える。ここまで来たら一旦データ採りまくって検証したいけど、狭い我が家では2mくらいが精いっぱいT_T。公園でやったら怪しいし、会社でやったら会社の資産だから掲載できないし、、、過疎ってる実家付近ならやり放題なんだけどなー、、、ちな、今回使っているモジュールは技適マークあるので違法電波にはならないよー


物理的制約のある中、無理難題をうまく解決するのがエンジニアリングだと思っている。元エンジニアでも管理職になるとエンジニアじゃなくなる人いるんだね。残念なことです。

nRF52833で測距(6) - IQデータの処理方法(3)



ちょっと本気出して測距を考えてみたい。IQデータの料理方法についてまとめておきたい。、、、の第3回目。相関係数の前処理について。空間平均法やる。

信号源が一つ(または反射による相関が極めて強い)場合、そのままでは相関行列のランクが不足するという数学的課題を解決するために前回Tamed Caponってのをやったけど、空間平均法もやってみる。空間平均法は行列のサイズを擬似的に小さくして平均化することで「ランク(情報の深み)」として復元する手法らしい。

空間平均法のアルゴリズム
全体のデータ数をN、サブアレイのサイズをMとして、M個の要素を持つ部分ベクトル$\mathbf{x}_i$を作成する。
全体データは
\[ \mathbf{x}=\begin{pmatrix} x_1,x_2,...,x_{N-1} \end{pmatrix}^T \] 以下のように部分ベクトルを作っていく \[ \mathbf{x}_{0}=\begin{pmatrix} x_0,x_1,...,x_{M-1} \end{pmatrix}^T \] \[ \mathbf{x}_{1}=\begin{pmatrix} x_1,x_2,...,x_{M+1-1} \end{pmatrix}^T \] \[ \mathbf{x}_{2}=\begin{pmatrix} x_2,x_3,...,x_{M+2-1} \end{pmatrix}^T \] \[ \dots \] \[ \mathbf{x}_{i}=\begin{pmatrix} x_i,x_{i+1},...,x_{M+i-1} \end{pmatrix}^T \] \[ \dots \] \[ \mathbf{x}_{L-1}=\begin{pmatrix} x_{L-1},x_{L-1+1},...,x_{M+L-1-1} \end{pmatrix}^T \] で \[ M+L-1-1=N-1 \] なので \[ L=NーM+1 \] で、各サブセットごとに$M \times M$の相関行列$\mathbf{R}_{{xx}_i}$を算出して、加算平均すると最終的な相関行列$\mathbf{\bar{R}}_{xx}$が得られるらしい。すなわち
\[ \mathbf{R}_{{xx}_i} = \mathbf{x}_i \mathbf{x}_i^H \tag{1} \] \[ \mathbf{\bar{R}}_{xx} = \frac{1}{L} \sum_{i=0}^{L-1} \mathbf{R}_{{xx}_i} \tag{2} \] なんでこれでランクが上がるのかをGeminiに聞いてみた
なぜこれで「ランク」が上がるのか
無線測距のデータがランク $1$ になってしまうのは、各周波数成分の位相関係が完全に固定(コヒーレント)されているからです。空間平均法で窓をずらしていくと、各サブセット $\mathbf{x}_i$ にとって「基準となる位相」が $i$ ごとに変化します。この「位相のずれ」を含んだ状態で平均をとることで、数学的には「信号源が統計的に独立であるかのように振る舞わせる」ことができ、行列のランクが回復(最大 $M$ まで)します。
、、、らしい(^∀^;)
で、これでもランクが足りない場合、「フォワード・バックワード空間平均(FBSS: Forward-Backward Spatial Smoothing)」というのをやるらしい。
Forwardとは(上に書いてあるのと同じ)、
\[ \mathbf{x}_{fi}=\begin{pmatrix} x_i,x_{i+1},...,x_{M+i-1} \end{pmatrix}^T \tag{3} \] Backwardとは、 \[ \mathbf{x}_{bi}=\begin{pmatrix} x_{M+i-1}^*,...,x_{i+1}^*,x_i^* \end{pmatrix}^T \tag{4} \] これにより新たに別の独立したデータを取得したようになるらしい。で、
\[ \mathbf{R}_{xxi} = \frac{\mathbf{x}_{fi}\mathbf{x}_{fi}^H + \mathbf{x}_{bi}\mathbf{x}_{bi}^H}{2} \tag{5} \] として、(2)の計算をすればいいってことらしい。
で、これをどう実装するかというと、上に記載したアルゴリズム通りに実装してもいいんだけど、オリジナルの$\mathbf{R}_{xx}$も欲しいってこともある。んで、オリジナルの$\mathbf{R}_{xx}$から部分行列を切り出し切り出しして足して足して最後に割って空間平均された相関行列$\mathbf{\bar{R}}_{xx}$を得ようと思う(参考サイト : 菊間信良著 科学技術出版社 アレーアンテナによる適応信号処理 FORTRAN, MATLAB ソースリスト)。
で、作成したコードがこちら
ble_spatial_rxx_capon2.py

解析に使ってるデータはこちら(今まで使いまわしてきたやつ...いちおう)
previous_log.txt

で、結果
いちおうこういう結果が出て、BeamformerよりCaponの方がまあ確かに鋭くはなったんだけど、空間平均のサブアレー要素数とか、Tamedの係数とかで、だらっとさせることもできるし、鋭さを求めると、別のピークが現れてきたり、めっちゃぶっ飛んだり、、、どういう設定にするかで結果が変わりやすいんだけど、じゃあその設定を何を根拠に調整していけばいいのかがわからない。実機でチューニングする類のやつなのかな( ˘•ω•˘ ).。oஇ


実は彼は天才で今週末でスパッと戦争を止められる秘策を持っていてほしい願望

2026年4月30日木曜日

nRF52833で測距(5) - IQデータの処理方法(2)



ちょっと本気出して測距を考えてみたい。IQデータの料理方法についてまとめておきたい。、、、の第2回目。

BeamformerができるんだったらCaponもできるのでは?って考えちゃう。んで、Caponってどんなんだったっけ?ってのは、、、Geminiに調べてもらった。前回はIQのフーリエ逆変換をどう理解するかっていう少し人間っぽい思考があった(まあわかってやってたんだけど)けど、今回はその必要がない(?)ので一気にGeminiに解説してもらう。
ってんで、こちら んで要点だけ抜き出すと
こちら、ステアリングベクトル(というらしい)
\[ \mathbf{a}(t) = \begin{pmatrix} 1 \\ e^{-j 2 \pi \Delta f t} \\ \vdots \\ e^{-j 2 \pi (N-1)\Delta f t} \end{pmatrix} \tag{1} \] ウェイトベクトル$\mathbf w$によって電力$P$は
\[ P=\mathbf w^H \mathbf R_{xx} \mathbf w \tag{2} \] って表されるんでした。見たい距離での出力を一定にしたうえで、$P$を最小化するってのがCapon法。それを数学的に書くと
\[ \min_{\mathbf{w}} \mathbf{w}^H \mathbf{R}_{xx} \mathbf{w} \quad \text{subject to} \quad \mathbf{w}^H \mathbf{a}(t) = 1 \tag{3} \] となるらしい。
これを解いて、Capon法のスペクトルは
\[ P_{CP}(t) = \frac{1}{\mathbf{a}(t)^H \mathbf{R}_{xx}^{-1} \mathbf{a}(t)} \tag{4} \] となるらしい。
(ステアリングベクトルって「距離によって位相差がこうなる」ってのを示していて、ステアリングベクトルの距離(すなわち$t$)をスイープすることで出力を最大化するってのがBeamformerでした。)
ところで、このCapon法は実は困ったことがあって、相関行列$\mathbf{R}_{xx}$の逆行列が存在しないってこと。今回IQデータのスナップショット数は1なので$\mathbf{R}_{xx} = \mathbf{x} \mathbf{x}^H$において$rnk(\mathbf{R}_{xx})=1$らしくて、これだと逆行列は存在しない。さらに測距において、LocalとRemoteのIQデータから得られる信号は、単一の経路(あるいは固定された反射路)を通っていて、強い相関(コヒーレンシー)を持っていて、いくらスナップショットを重ねても、位相関係が固定されているので、情報は重なったまま(コヒーレントなまま)で、行列のランクが上がらないってのも問題。これを解決するには
  1. 空間平均法=サブアレー的な処理をして信号間の相関を崩す
  2. 複数シーケンス=独立した複数のデータ取得で様々な要因を取り込んで信号間の相関を崩す
  3. 対角成分付加法=数学的には固有値の底上げ
ていうアイデアがあるらしいんだけど、3が簡単そうなのでやってみる。1が正攻法っぽいけど、3は確実に逆行列を安定して得られるという点で良い方法らしい。ちな、「Tamed Capon」とか「Diagonal Loadingを適用したRobust Capon Beamforming」とかいうらしい。

ble_tamedcapon.py


あれ?するどくなってる?なってないような、、、σ( ̄∇ ̄; )
やっぱり空間平均法もやってみるかー


ほんとまじで戦争やめて!
○○○○が○○○○○の首をとって○○○に謝ればいいのに