社会課題克服案:ESP32 + 加速度センサー:常時監視 → 異常時FFT → サーバ送信(実装設計まとめ)

ESP32 + 加速度センサー 常時監視 → 異常時FFT → サーバ送信(設計まとめ)

狙い:FFTを常時回さず、軽い異常検知でトリガして FFT を必要時だけ実行し、イベントをサーバへ送る。

はじめに:社会課題と「こんなのあったらいいな」

監視したい場所ほど、人手が足りません。見回りや点検が必要な場所は増える一方なのに、現場の人数は減り、移動時間もコストも重くなる。 しかも災害や強風・豪雨の後は「どこから見に行く?」が悩みのタネになります。

社会課題(現場で起きていること)

  • 人手不足で「定期点検の頻度を上げられない」。
  • 異常が起きたあとに駆けつけるが、どこが危ないのか分からないので優先順位がつけづらい。
  • 「たぶん大丈夫」と「やっぱり危ない」の間に、判断の根拠が薄い。
  • 監視システムを入れても、誤検知が多いと運用が破綻する(鳴りすぎる警報は嫌われる)。

こんなのあったらいいな(理想の姿)

平常時は静かに見守り、異常の兆しだけを拾って、「何が起きたか」を説明できる形で記録してくれる。 そして必要な情報だけを自動でサーバに送って、あとから比較・分析できる――。

要望を一言にすると:
「見回りに行く前に、行くべき場所と“根拠”が分かる仕組みがほしい。」

だったら、こんなの考えてみた

そこで、ESP32 + 加速度センサーで常時監視しつつ、 平常時は軽い指標で監視し、怪しい瞬間だけFFTで“中身”を出す構成を考えました。 さらに、その結果をイベントとしてサーバに送れば、現場の判断と説明が一気に楽になります。

1. 目的と方針(結論)

  • 加速度センサーをESP32に接続して常時監視する。
  • 「おかしい」状態になった瞬間だけFFTを実行し、周波数特徴(ピークHz・帯域エネルギーなど)を算出する。
  • 算出した特徴量(必要なら生波形の一部)を特定サーバへ送信する。

なぜFFTは常時やらない?

  • FFTは重い(CPU・電力・通信・誤検知のコストが増える)。
  • 「異常の入口」はFFTより軽い指標(RMS/分散/ピーク/継続時間)で十分検知できる。
  • FFTは「原因の説明」「分類」「レポート」に強い。トリガ後に回すのが合理的。
推奨サンプリング 構造物/地震:100〜400Hz / 機械振動:〜1kHz(目的次第)
推奨FFT点数 256 or 512(分解能=Fs/N)
リングバッファ 常に最新10秒分程度(イベント前後を切り出す)
送信 異常時のみ HTTP POST(またはMQTT)

3. アーキテクチャ(壊れにくい構成)

[Sampler] 等間隔サンプリング(最重要) ↓ (a(t) をリングへ) [Detector] 軽量異常判定(RMS/分散/ピーク/継続時間) ↓ (閾値超えでイベント発火) [FFT Worker] イベント時のみFFT(ピークHz/帯域エネルギー等) ↓ [Uploader] HTTP POST / MQTT 送信(失敗時リトライ / キュー)

タスク分割(ESP32の勝ち筋)

  • Sampler:タイマー割り込み or 高優先度タスク(等間隔を守る)
  • Detector:短窓で指標を更新(軽い)
  • FFT Worker:トリガ時にリングバッファから切り出してFFT
  • Uploader:通信は別スレッド。サンプル取得を邪魔しない

リングバッファ(常時保存)

  • 例:Fs=200Hz、10秒 → 2000点保持
  • イベント時:直前2秒 + 直後2秒 などを切り出す(「何が起きたか」説明に効く)

5. FFTで出すべき「使える」特徴量

FFTの生スペクトル全部送ると通信が太る。まずは特徴量だけで十分。

推奨(最低限)

  • peak_hz:最大ピーク周波数
  • peak_mag:ピーク振幅
  • band_energy:帯域別エネルギー(例:0–5Hz / 5–15Hz / 15–30Hz)
  • rms:イベント窓のRMS
  • duration_ms:異常継続時間

FFT前処理(必須)

  • DC除去:平均を引く(0Hzの山を潰す)
  • 窓関数:Hamming/Hann(漏れを減らす)
  • FsとNは固定して、サーバ側で比較可能にする

周波数分解能の目安

freq_resolution = Fs / N

例:
Fs=200Hz, N=512 → 0.39Hz刻み
Fs=400Hz, N=512 → 0.78Hz刻み

7. 実装の要点(落とし穴だけ先に潰す)

等間隔サンプリングが命

  • NG:loopでセンサー読み → 時間がブレる(FFTが嘘になる)
  • OK:タイマー割り込み or 高優先度タスクで周期固定

通信でサンプリングを止めない

  • Wi-Fi/HTTPは遅延が出る。Samplerと同じスレッドでやるとデータが欠ける。
  • Uploaderは別タスク。送信キューを持つ。

再送(現場で必須)

  • 送信失敗時はキューに残す
  • 堅くやるならSPIFFS/Flashに一時退避(電源断でも残す)

時刻

  • NTPで時刻合わせ(イベントの突き合わせができる)

付録:イベント処理フロー(擬似コード)

// Sampler: Fs固定で加速度取得 → ringへ
a = accel_to_motion_component(x,y,z)    // |a|-1g 等(後で改善可能)
ring.push(a)
detector.feed(a)

// Detector: 短窓RMS + 継続時間
rms = detector.rms_0_5s()
if (rms > baseline_rms * TH && over_ms >= HOLD_MS) {
  event_id = new_id()
  fftQueue.push({event_id, now_ms})
}

// FFT Worker: ringから直近N点+前後を切り出し
buf = ring.slice(last N points or pre/post)
buf -= mean(buf)
window(buf)
mag = FFT(buf)
features = extract_peak_and_band_energy(mag)

// Uploader: JSON送信(失敗時リトライ)
payload = build_payload(device_id, ts, features, ...)
post_json(SERVER_URL, payload)
このHTMLは「設計まとめ」用。実装に落とす場合はセンサー型番(I2C/SPI/アナログ)とサーバ方式(HTTP/MQTT)を確定させる必要あり。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA