
Wi-Fiルーターが人の呼吸を「見ている」と言われても、最初はSFじみた話に聞こえます。 でも仕組みを理解すると、むしろ「なぜ今まで使われていなかったのか」と思えてくる技術です。
カメラもPIRセンサーも不要で、既存のWi-Fi電波だけで在室検知・呼吸モニタリングができる。 それを実現するのがWi-Fi CSI(Channel State Information)を使ったパッシブセンシングで、RuView はそのパイプライン全体をRustで実装したライブラリです。
Pythonエコシステム(CSIToolやNexmon CSI)でCSI研究の蓄積があるにもかかわらず、あえてRustを選んだ理由は何か。 その答えを物理層から実装層まで順に解きほぐしていきます。
Wi-Fi CSIが「人の存在」を読み取れる理由
Wi-Fiの電波強度を示す指標としてRSSIはよく知られています。 ただしRSSIは「今どれくらい強い電波が届いているか」を1つのスカラー値で表すだけで、信号の内部構造は見えません。
CSIはまったく異なる情報を持っています。 OFDM変調を使う現代のWi-Fi(802.11n以降)は、1つのチャネルを複数のサブキャリアに分割して並列送信します。 CSIはそのサブキャリアごとに、振幅と位相を含む複素数ベクトルとして伝搬状態を記録します。
- RSSI:チャネル全体の受信電力をスカラー値1つで表現。人が動いても変化は粗い
- CSI:サブキャリア単位(数十〜数百本)の複素数ベクトル。空間的な多様性が高く、微細な変化を捉えられる
人が室内を移動すると、壁・床・家具からの反射経路(マルチパス)が変化します。 この変化がCSIの振幅・位相パターンに現れるため、「誰かがいる」「動いた」という情報を電波から読み取れます。
さらに精度が上がるのが呼吸・心拍の検知です。 胸郭の動きは数mm〜数cmという微小変位ですが、Wi-Fi電波の波長(2.4GHz帯で約12.5cm)に対して無視できないスケールです。 この微小変位が、特定サブキャリアの位相に周期的な変動として現れます。
呼吸は0.1〜0.5Hz、心拍は0.8〜2.0Hz程度の周波数帯域に対応するため、FFT処理で分離できます。 単一周波数では人体の位置によって「たまたま位相変化が小さい」ケースが生じますが、複数サブキャリアを束ねることで空間的な多様性が確保され、どれかのサブキャリアが変化を捉えられる確率が上がります。
RuViewのアーキテクチャ:CSIストリームから空間インテリジェンスへ
RuViewのパイプラインは、大きく4つのレイヤーで構成されています。
CSI取得レイヤーでは、ESP32-S3またはESP32-C6がWi-Fiチャネルのサブキャリア情報をリアルタイムに収集し、UDPパケットとしてネットワークに送出します。 ESP32-C6-DevKitは1枚あたり6〜10ドル程度で入手でき、Wi-Fi 6(802.11ax)に対応しています。
信号処理レイヤーでは、RustのセンシングサーバーがUDP 5005番ポートでCSIフレームを受信し、フィルタリング・特徴抽出を行います。
パイプラインの骨格を示す概念コードを以下に示します(RuViewの実際のコードではなく、構造を理解するための擬似コードです)。
// 概念コード:RuViewの実装ではなく、パイプライン構造を示す擬似コードです
use tokio::net::UdpSocket;
use tokio::sync::mpsc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let socket = UdpSocket::bind("0.0.0.0:5005").await?;
let (tx, mut rx) = mpsc::channel::<CsiFrame>(256);
// 受信タスク:UDPソケットからCSIフレームを読み取りチャネルへ送信
tokio::spawn(async move {
let mut buf = [0u8; 4096];
loop {
if let Ok((len, _addr)) = socket.recv_from(&mut buf).await {
if let Ok(frame) = CsiFrame::decode(&buf[..len]) {
let _ = tx.send(frame).await;
}
}
}
});
// 処理タスク:フレームを受け取り信号処理パイプラインへ
while let Some(frame) = rx.recv().await {
let features = extract_features(&frame); // フィルタリング・FFT等
infer_presence(&features); // 在室/バイタル推論
}
Ok(())
}
実際のRuViewでは、フレーム受信からデコード・特徴抽出までが非同期タスクとして分離されており、このコードよりも多層の処理が入ります。
推論・分類レイヤーでは、処理済みの特徴量が「WorldGraph」と呼ばれるJSONスナップショット形式に変換されます。
scripts/ruview_occ_dataset.py がWorldGraph JSONをOccWorldフォーマットのテンソルに変換し、屋内クラスのリマッピングとゼロego-posesを付与して再学習パイプラインに流せる構成になっています(ADR-147 Phase 3)。
出力レイヤーでは、在室検知・バイタルサイン・ポーズ推定の結果がAPIとThree.js UIを通じて提供されます。 GitHubに公開されている実測値として、MM-Fiポーズモデルがtorso-PCK@20で82.69%(シングル)・83.59%(アンサンブル+TTA)を達成しています。 75Kパラメータのマイクロバリアントでも74.30%を記録しており、軽量化と精度のトレードオフを選択できます。
パイプライン全体の構成をまとめると次のとおりです。
- CSI取得:ESP32ファームウェア → UDP 5005でストリーム送出
- 信号処理:Rustセンシングサーバーでフィルタリング・特徴抽出
- 推論:WorldGraph JSON → OccWorldテンソル変換 → 分類
- 出力:在室検知 / 呼吸・心拍 / ポーズ推定
- 開発環境:
CSI_SOURCE=simulatedでDockerシミュレーションモード(実ハード不要)
Dockerイメージはamd64とarm64のマルチアーキテクチャ対応です。 実CSIとシミュレーションの差分は意識しておく必要がありますが、アルゴリズムの検証やUIの開発は実ハードなしに進められます。
なぜRustなのか:PythonツールチェーンとRust実装の設計上の差分
CSIセンシングの研究コミュニティはPythonで積み上がっています。 Linux mac80211ドライバを使うCSIToolや、Broadcomチップ向けのNexmon CSIなど、先行ツールは軒並みPythonエコシステムと親和性が高い。 なぜRuViewはRustを選んだのか。
最初の問題は**GIL(Global Interpreter Lock)**です。 CPythonのGILは、複数スレッドが同時にPythonオブジェクトを操作することを禁止します。 CSIフレームは高頻度で届くストリームデータで、受信・デコード・フィルタリング・推論を並列に処理したい場面が多い。 GILの制約下では真の並列処理はmultiprocessingに頼らざるを得ず、プロセス間通信のオーバーヘッドが発生します。
# Python: GILのため threading では並列化できない
# multiprocessing を使うとプロセス間通信コストが発生する
from multiprocessing import Process, Queue
def process_csi_frames(queue: Queue):
while True:
frame = queue.get() # プロセス間でのデータコピーが発生
features = extract_features(frame)
infer(features)
// Rust: tokio + rayon で真の並列処理
// 受信タスクと処理タスクが独立したスレッドで動作
// データはチャネルで安全に共有
// GCポーズなし・プロセス間コピーなし
Rustでは tokio の非同期ランタイムと rayon のデータ並列処理を組み合わせることで、GILなしの真の並列処理が実現します。
フレーム受信・デコード・特徴抽出・推論が独立したタスクとして動作し、コアを余さず使えます。
次の問題はGCポーズです。 Pythonにはガベージコレクターがあり、メモリ回収のタイミングで処理が一時停止します。 リアルタイムセンシングでは、このGCポーズが呼吸・心拍の周期検出に影響するレイテンシスパイクになりえます。 Rustはコンパイル時の所有権システムでメモリ管理を行うため、GCポーズが存在しない。 予測可能なレイテンシはリアルタイム信号処理の基本要件です。
クロスコンパイルと組み込み展開も大きな差分です。 Rustはarm64やRISC-Vへのクロスコンパイルが標準ツールチェーンでサポートされています。 ESP32のLP-coreで動くRISC-Vプログラム(モーションゲート)もRuViewのコードベースに含まれており、センサーノード側の処理もRustで書けます。 Pythonランタイムを組み込みデバイスに載せることの難しさと比べると、この差は実務で効いてきます。
メモリ安全性は長時間稼働のシナリオで意味を持ちます。 介護施設や工場での24時間稼働を想定すると、バッファオーバーフローやデータ競合によるクラッシュは許容できません。 Rustのコンパイル時チェックは、マルチスレッドのCSIストリーム処理でのデータ競合をビルド時に検出します。
このパターンは他の領域でも実績があります。
Hugging Faceの tokenizers ライブラリはPythonで研究・開発し、Rustで本番実装するアプローチを採用しており、純粋なPython実装と比べて約20倍の高速化を達成しています。
CSIセンシングも「研究はPython・本番はRust」という分業が自然な流れです。
ひとことで言えば、GIL・GCポーズ・クロスコンパイルの3点がRust選択の実質的な理由です。
- GILと並列処理:CPythonのGILが真の並列ストリーム処理を阻む。Rustはスレッド並列をネイティブサポート
- GCポーズとレイテンシ:Pythonのガベージコレクションがリアルタイム処理のレイテンシスパイクを生む。Rustにはない
- クロスコンパイル:arm64/RISC-Vへの展開がRustの標準ツールチェーンで完結する
- メモリ安全性:長時間稼働・マルチスレッドストリームでのバグをコンパイル時に検出
- 研究→本番の分業:PythonでプロトタイプしRustで本番化するパターンは他領域でも確立済み
実務ユースケースと、正直に言うべき制約
技術の可能性を語るだけでは実務判断の役に立ちません。 3つのシナリオと現時点での制約を並べます。
介護見守り・工場無人確認・オフィス入退室管理
介護見守りは、CSIセンシングが最も「刺さる」シナリオです。 カメラは「見られている感」への抵抗が強く、特に寝室・浴室では導入が難しい。 CSIセンシングが生成するのは電波伝搬係数のベクトルデータであり、映像データではありません。 「何のデータが生成されるか」という技術的な差分が、プライバシーリスクの構造そのものです。
実務での構成イメージは、ESP32-C6を居室の壁面コンセントに固定し、既存の家庭内Wi-Fiルーターとは別のセンシング専用SSIDを立てる形です。 UDPストリームをローカルのRustサーバーで処理し、クラウドには在室フラグと呼吸レートだけを送る構成にすれば、生の電波データが外部に出ることはありません。 ただし1人の呼吸・心拍は比較的安定して取れますが、複数人が同空間にいる場合の個人分離は難しく、「誰が」ではなく「誰かがいる」という粒度での利用が現実的です。
工場の無人確認では、危険区域への立ち入り検知や夜間の不審者検知に使えます。 PIRセンサーは熱源の動きを検知しますが、死角が生じやすく、広い空間のカバーには複数台が必要です。 1台のWi-FiアクセスポイントがカバーするエリアをCSIで監視できれば、センサー台数を削減できます。
オフィスの入退室管理では、座席の在席確認や会議室の利用状況把握が想定されます。 バッジシステムと組み合わせることで、「カードはあるが人がいない」状態の検知も可能です。
現時点の制約を正直に
最初のハードルは対応ハードウェアの限定性です。 CSIを取得するには、CSI出力をサポートするファームウェアが必要です。 RuViewが動作確認しているのはESP32-S3とESP32-C6で、汎用のWi-FiルーターやPCのNICからCSIを取得するには別途対応ファームウェアが必要になります。
重要な注意点として、RuViewのWindowsパスはCSIではなくRSSIベースです。
Windowsの WindowsWifiCollector はRSSI(-39dBm、リンク品質94%など)を取得し、分散・モーションエネルギーで在室を判定する実装になっています。
CSIの豊富な情報量を活かした処理ではないため、精度面での期待値は異なります。
マルチパス環境依存の精度ばらつきも避けられません。 CSIの変化パターンは部屋の形状・家具配置・壁材によって大きく変わります。 あるオフィスで調整したモデルを別の部屋に持ち込むと、再キャリブレーションが必要になるケースが多い。
複数人環境での分離精度は現時点での研究課題です。 複数人分離の精度については研究段階であり、WiMANSのような公開データセットを使った研究が進んでいますが、実用レベルの個人分離には至っていないのが現状です。
ネットワーク構成の制約も実務では効いてきます。 ESP32からのCSIストリームはUDP 5005番ポートを使います。 企業ネットワークでは、センシング用のSSIDを業務ネットワークから分離する構成が現実的です。 ESP-NOWを使ったクロスボードメッシュ(ESP32-C6同士の同期)は99.56%のマッチ率・104μsの平滑化オフセット標準偏差を達成していますが、この精度を維持するには電波環境の安定性が前提になります。
- 対応チップの限定:ESP32-S3/C6など、CSI対応ファームウェアが必要。汎用NICは不可
- WindowsパスはRSSIベース:CSIの情報量を活かした処理ではない
- 環境依存の精度ばらつき:部屋ごとのキャリブレーションが必要になるケースが多い
- 複数人分離の限界:1人環境では有効だが、複数人の個人分離は研究段階
- ネットワーク分離の推奨:センシング用SSIDを業務ネットワークから分けるのが現実的
CSIセンシングの現時点での「旬」は、1人環境でのカメラ代替です。 介護の寝室・工場の危険区域・会議室の在席確認——いずれも「映像を撮りたくないが存在は知りたい」という構造的なニーズがあり、10ドルのESP32-C6とRustサーバーで試せるコストは評価のハードルを大きく下げます。 複数人分離や汎用ハードウェア対応は今後の課題ですが、まずDockerシミュレーションで動かし、次にESP32-C6を1枚買って実CSIを流してみる——その2ステップで技術の実態は十分つかめます。
株式会社ホコサキは山口県宇部を拠点に、AI活用支援・業務システム開発・DX推進に取り組んでいます。 CSIセンシングのような新技術の実務適用可能性の評価や、Rustを含む技術スタック選定のご相談は お問い合わせページ からどうぞ。

