本文へスキップ
株式会社オープンナレッジ
株式会社オープンナレッジ Open Knowledge Inc.
福祉生体工学・リアルタイムデジタル信号処理(DSP) 8ch sEMG / Biquad IIR Notch / 256-pt STFT / Rust #![no_std] 対象:ろう者・難聴者支援に関わる方・医療福祉関係者様・研究者様

前腕8ch表面筋電位(sEMG)と手話非手指動作(NMM)のリアルタイム信号処理: 双二次IIRノッチフィルタと256点STFT実装

監修:加藤 明生(株式会社オープンナレッジ 創業者・代表取締役CTO / 上級医療情報技師 / 登録情報処理安全確保支援士(第007617号))

1. 基本と全体像

この記事の要点と4つの章のご案内

身近なたとえで見る仕組み:「5本の指を動かす腕の中のピアノ線」と「雑音だけを取り除く落ち着いた聴診器」に関するイメージ写真
身近なたとえで見る仕組み:「5本の指を動かす腕の中のピアノ線」と「雑音だけを取り除く落ち着いた聴診器」
現場で陥りやすい落とし穴と回避策:生体信号処理と手話情報アクセシビリティの3つの要点に関するイメージ写真
現場で陥りやすい落とし穴と回避策:生体信号処理と手話情報アクセシビリティの3つの要点
前腕8ch表面筋電位(sEMG)と手話非手指動作(NMM)のリアルタイム信号処理: 双二次IIRノッチフィルタと256点STFT実装 の各章におけるテーマと要点一覧表
章構成 主なテーマ 要点と確認ポイント
1. 基本と全体像 身近なたとえで見る仕組み:「5本の指を動かす腕の中のピアノ線」と「雑音だけを取り除く落ち着いた聴診器」 災害時の避難所や救急医療の現場で、ろう者・難聴者の方がカメラの設置を気にせず手話で対話できるよう、前腕の8チャンネル表面筋電位(sEMG)を用いたウェアラブル支援技術(moshimo)を研究開発しています。
2. 現場での進め方と対策 現場で陥りやすい落とし穴と回避策:生体信号処理と手話情報アクセシビリティの3つの要点 皮膚表面で計測される微弱な筋電信号(20〜450Hz)から商用電源ハムノイズ(50Hz/60Hz)をリアルタイム除去するため、双二次(Biquad)直接形II転置IIRノッチフィルタを実装しています。
3. 関連する制度とルール なぜ手話の認識に「カメラの映像」だけでなく「腕の筋電センサー(sEMG)」を組み合わせるのですか? さらにハニング窓を用いた256点短時間フーリエ変換(STFT)と9軸IMU(姿勢角)を統合し、手話文法に不可欠な非手指動作(NMM)と指文字を遅延20ミリ秒以下で特徴量化します。
4. 詳しい技術仕様としくみ 手話における「非手指動作(NMM:Non-Manual Markers)」とは何ですか?なぜそんなに大切なのですか? カメラだけで手話を読み取ろうとすると、「自分の部屋や外出先で常にカメラを向けられ続けるプライバシーの負担」「暗い場所や逆光で見えなくなる問題」「手と手が重なったときに指の形が隠れてしまう問題(オクルージョン)」が起きます。リストバンド型の8チャンネル表面筋電位(sEMG)センサーなら、カメラの死角や照明に関係なく、指を動かす筋肉の微弱な電気信号から直接、繊細な指の動きや力の入れ具合を読み取ることができます。
第1章〜第4章では、実務チェックリスト・公的制度基準・詳しい技術仕様を確認できます。
この記事のポイント
  • 01 災害時の避難所や救急医療の現場で、ろう者・難聴者の方がカメラの設置を気にせず手話で対話できるよう、前腕の8チャンネル表面筋電位(sEMG)を用いたウェアラブル支援技術(moshimo)を研究開発しています。
  • 02 皮膚表面で計測される微弱な筋電信号(20〜450Hz)から商用電源ハムノイズ(50Hz/60Hz)をリアルタイム除去するため、双二次(Biquad)直接形II転置IIRノッチフィルタを実装しています。
  • 03 さらにハニング窓を用いた256点短時間フーリエ変換(STFT)と9軸IMU(姿勢角)を統合し、手話文法に不可欠な非手指動作(NMM)と指文字を遅延20ミリ秒以下で特徴量化します。
場面別の実務確認ポイント 全訪問者対応・3段階の構成
01 ろう者・難聴者の方・手話通訳者・自治体福祉ご担当の方

なぜ「単語の置き換え」だけでは手話の本当のニュアンス(疑問・否定・感情を表す非手指動作 NMM)が伝わらないのか、技術がどう寄り添うのかを視覚図解で解説します。

02 医療・看護・防災・リハビリテーション現場の方

電極の接触インピーダンス変化(汗や乾燥)、関西(60Hz)と関東(50Hz)の電源周波数切替、オフライン環境での動作など、現場実装の工夫を確認できます。

03 生体工学研究者・組み込みRustエンジニアの方

後半の「第3章 Monograph」にて、Z領域伝達関数 H(z)、双一次変換係数導出、Direct Form II Transposed 差分方程式、Rust #![no_std] DSP コードを詳解しています。

第1章:Overview & Visual Architecture

身近なたとえで見る仕組み:「5本の指を動かす腕の中のピアノ線」と「雑音だけを取り除く落ち着いた聴診器」

手首から肘にかけての「前腕(ぜんわん)」に軽くもう片方の手を当てて、親指や小指をグッと動かしてみてください。腕の中の筋肉(浅指屈筋や総指伸筋など)が、まるで「5本の指を操るピアノ線」のように一本ずつ別々に動くのがわかります。

人間の脳が「指を動かそう」と命令を出すとき、その筋肉にはごくわずかな電気信号(筋電位:ミリボルト単位)が流れます。この電気信号を皮膚の上から8個のセンサーでぐるりと聞き取るのが「8チャンネル表面筋電位(sEMG)」です。これなら、カメラの前に立たなくても、ポケットの中や暗い夜道でも、どの指にどれくらい力を入れたかが正確にわかります。

ただし、この筋肉の電気信号はとても小さいため、そのまま測ると部屋の蛍光灯やコンセントから出ている電気の波(東日本では1秒間に50回、西日本では60回の「ブーン」というハムノイズ)にかき消されてしまいます。そこで私たちは、「双二次IIRノッチフィルタ」という数学のろ過器を使って50Hz/60Hzの雑音だけをピンポイントで消し去り、さらに「256点STFT(短時間フーリエ変換)」によって1秒間に数十回という速さで筋肉の音色(周波数スペクトル)を読み解く仕組みをRust言語で実装しています。

ポイント 01 サンプリング周波数(ナイキスト定理)
1,000 Hz × 8 ch

骨格筋の主要な活動帯域(20Hz〜450Hz)を歪みなく捉えるため、シャノン・ナイキストの標本化定理に基づき毎秒1,000回の高速計測を行います。

ポイント 02 商用電源ノイズ減衰量(50Hz / 60Hz)
-40 dB 以上の除去

Q値(先鋭度)を高めた双二次IIRノッチフィルタにより、隣接する大切な筋電成分を傷つけずに50/60Hzの電源ノイズだけを100分の1以下に減衰させます。

ポイント 03 エンドツーエンド信号処理遅延
20 ミリ秒以下

動的メモリ確保を行わないRust固定長リングバッファにより、手話の自然な会話テンポを妨げないリアルタイム応答を実現します。

図解:前腕8ch表面筋電位(sEMG)+ 9軸慣性センサー(IMU)から手話表現(手指+NMM)へ変換するDSPパイプライン
01 前腕8ch生体計測 前腕断面 8極 入力信号 (f_s = 1000Hz) ・浅指屈筋 / 総指伸筋電位 ・50/60Hz 電源ハム混入 ・基線変動 (0〜15Hz) 02 双二次IIRフィルタ段(Direct Form II) 50Hz / 60Hz ノッチフィルタ H(z) y[n] = b0*x[n] + w1[n-1] 商用電源ノイズと高調波(100/120Hz)を 位相歪みを抑えてピンポイント減衰 256点 ハニング窓 STFT & 特徴量 w[n] = 0.5*(1 - cos(2*pi*n/255)) RMS(筋収縮強度)・MDF(中央周波数)・ スペクトル包絡を64点ホップで連続抽出 03 手話音韻・非手指動作(NMM)統合 手指形状(Handshape)推定 8ch間の共収縮パターン行列から カメラの死角でも指文字・屈曲を識別 プライバシー配慮(カメラ映像不要) NMM(文法マーカー・強調度)反映 筋緊張度(Isometric Tension)と 加速度変化から疑問・否定・強意の 手話特有の文法ニュアンスを保持
比較項目一般的なカメラ映像のみの手話認識当社研究(moshimo):前腕8ch sEMG + DSPエッジ処理
プライバシーと心理的負担常に顔や部屋の中をカメラで撮影し続ける必要がある腕のリストバンドのみで動作し、カメラ撮影が不要な場面でも使える
指の重なり(オクルージョン)・暗所両手が重なったり夜間・停電時になると認識精度が急落する筋肉の電気信号を直接測るため、照明ゼロや死角でも安定して計測可能
力の入れ具合(強意・緊張度)の検出見た目の位置が同じだと「軽く握る」と「強く握る」を区別できない振幅(RMS)と周波数帯域から「痛みや緊急度の強さ」まで識別できる
通信途絶時(災害避難所)の動作大型クラウドGPUへ動画を送る方式は圏外になると使えないRust製の軽量DSPにより、端末内(エッジ)だけで高速・省電力に動作
第2章:Practical Field Guide & Self-Check

現場で陥りやすい落とし穴と回避策:生体信号処理と手話情報アクセシビリティの3つの要点

落とし穴 01:日本手話(JSL)を「日本語の音声の単語をそのまま順番に手の形に置き換えたもの」だと誤解してシステムを作ってしまう

回避策:独自の文法体系を持つ独立した言語として敬意を払い、非手指動作(NMM)と空間文法を設計の中心に据える

技術者が手話支援ツールを作る際に最も陥りやすい過ちが、「手の形=1文字・1単語」という単純な辞書変換だけで完結させようとすることです。日本手話では、同じ手の動きであっても、眉を上げるか下げるか、顎を引くか、あるいは動作のスピードと止め(ホールド)の強さによって、「行きますか?(疑問)」「行きません(否定)」「原則として行く!(強い意志)」が区別されます。当事者の方々の声に耳を傾け、この繊細なリズムと強弱(sEMGの振幅包絡と静止保持時間)を損なわない設計が不可欠です。

落とし穴 02:腕を振ったときの「揺れノイズ(モーションアーチファクト:0〜20Hz)」で波形が大きく暴れてしまう

回避策:20Hzハイパスフィルタによる基線ドリフト除去と、50/60Hzノッチフィルタの直列カスケード構成

手話は腕全体を大きく動かすため、電極と皮膚がわずかにズレることで発生する「低周波の大きなうねり(0〜15Hzのモーションアーチファクト)」が必ず混入します。これを除去しないまま平均や二乗和(RMS)を計算すると、指を動かしていなくても「腕を振っただけ」で大きな信号が出たと誤判定してしまいます。前段で20Hz以下の揺れをカットし、続いて50Hz(東日本)または60Hz(西日本・高槻)の商用電源ノイズを双二次IIRフィルタで除去する2段構えが重要です。

落とし穴 03:フーリエ変換(FFT/STFT)を行う際、データをそのまま四角く切り出してしまい「スペクトル漏れ」が起きる

回避策:256サンプル窓の両端を滑らかにゼロへ絞る「ハニング窓(Hanning Window)」と75%オーバーラップの適用

連続している筋肉の電気信号を256ミリ秒ごとにブツッと切り出して周波数解析にかけると、切り口の段差によって本来存在しないはずの高い周波数ノイズ(サイドローブ・スペクトル漏れ)が大量に発生します。これを防ぐため、窓の両端をコサイン曲線で滑らかに減衰させる「ハニング窓」を掛け合わせ、さらに64サンプル(64ミリ秒)ずつ窓をずらしながら重ねて解析(75%オーバーラップ)することで、一瞬の指の動きも取りこぼさずに捉えます。

今日から確認できる!ろう者・難聴者の方に配慮した職場・窓口のアクセシビリティ 3項目チェック

達成度: 0 / 3

クリックしてチェックを入れると、職場やWebサイトの情報バリアフリー度に応じたアドバイスが表示されます。

上の3項目をクリックして、現在のWebサイトや窓口のアクセシビリティを点検してみてください。

8ch sEMG ノッチフィルタ&STFT リアルタイム処理検証マトリクス

西日本(60Hz:大阪府高槻市等)および東日本(50Hz)の商用電源ハムノイズ抑制と、256点STFTによる特徴量抽出の品質検証基準です。

検証項目 対象周波数・パラメータ 減衰量・レイテンシ基準
商用電源ハム除去(西日本/東日本) f0 = 60.0 Hz / 50.0 Hz (Q = 30.0) 中心周波数において -40 dB 以上の減衰、隣接運動単位帯域の位相歪み最小化
基線動揺(モーションアーチファクト)除去 High-Pass fc = 20.0 Hz (2nd-Order) 腕の振りやケーブル揺れに起因する 0〜15 Hz 低周波ドリフトの確実に遮断
エッジ推論・特徴量フレーム更新周期 N = 256 pt Hanning / Hop R = 64 pt 64 ms 周期(15.625 Hz)で8chスペクトル特徴量(RMS/MDF/MNF)をヒープ割り当てゼロで算出
関連コラム・豆知識

筋肉が疲れてくると、電気信号の「音の高さ(中央周波数 MDF)」がだんだん低くなる?

実は、256点STFT(短時間フーリエ変換)で筋肉の電気信号の周波数を分析すると、「どの指を動かしたか」だけでなく「その人の腕がどれくらい疲れているか(筋疲労度)」までリアルタイムにわかります。筋肉が元気なときは100Hz〜150Hzあたりの高い周波数の信号が活発に出ますが、長時間手話を続けたり重い荷物を持ったりして筋肉に乳酸などの疲労物質が溜まってくると、筋繊維を伝わる電気のスピード(筋線維伝導速度)がゆっくりになり、周波数スペクトルの中心(MDF:Median Frequency)が60Hz〜80Hzの低い方へとスライドしていくのです。この性質を応用すると、「使いすぎによる腱鞘炎や疲労を事前に知らせてくれる配慮した見守り機能」も実現できます。

技術仕様・実装解説:Technical Architecture & Implementation — Biquad IIR Notch Transfer Function H(z), Direct Form II Transposed & 256-Point STFT

前腕8ch sEMG 用 双二次IIRノッチフィルタ伝達関数 H(z)・Direct Form II 転置差分方程式と 256点ハニング窓 STFT の Rust 2024 実装

f_s = 1000Hz / Q = 30.0 / N_FFT = 256
Sampling & Bandwidth f_s = 1000 Hz (20..450 Hz)
Notch Zero Placement z = exp(±j*2π*f_0/f_s)
STFT Window & Hop 256-pt Hanning / 64-pt Hop
Memory Footprint #![no_std] Zero Heap Alloc
1. 設計仕様・数理モデル(Z-Domain Transfer Function H(z), Bilinear Transform Coefficients & Short-Time Fourier Transform)

標本化周波数 fs = 1000 Hz において、商用電源周波数 f0 ∈ {50 Hz, 60 Hz} を減衰させる2次IIRノッチフィルタ(双二次フィルタ:Biquad Filter)は、角周波数 ω0 = 2π f0 / fs と品質係数(先鋭度)Q = 30.0、減衰帯域幅パラメータ α = sin(ω0)/(2Q) を用いて、単位円上の零点 z = exp(±jω0) と単位円内側の近傍極を持つ以下の Z 領域伝達関数 H(z) として定式化されます:

H(z) = (b0 + b1 z-1 + b2 z-2) / (1 + a1 z-1 + a2 z-2) = (1 - 2 cos(ω0) z-1 + z-2) / ((1 + α) - 2 cos(ω0) z-1 + (1 - α) z-2)
b0 = 1 / (1 + α),   b1 = -2 cos(ω0) / (1 + α),   b2 = 1 / (1 + α),   a1 = -2 cos(ω0) / (1 + α),   a2 = (1 - α) / (1 + α)

単精度浮動小数点(f32)環境での内部状態オーバーフローと量子化雑音を抑えるため、実装には遅延レジスタ2個(w1, w2)のみで動作する直接形II転置構造(Direct Form II Transposed)を採用します。時刻 n における各チャンネル c ∈ {0,…,7} の差分方程式は以下で与えられます:

yc[n] = b0 xc[n] + wc,1[n-1],   wc,1[n] = b1 xc[n] - a1 yc[n] + wc,2[n-1],   wc,2[n] = b2 xc[n] - a2 yc[n]
Xc(m, k) = Σn=0..N-1 yc[mR + n] · wHann[n] · exp(-j 2π k n / N),   wHann[n] = 0.5 · (1 - cos(2π n / (N - 1)))

ここで窓長 N = 256(256 ms、周波数分解能 Δ f = 1000 / 256 = 3.90625 Hz)、ホップサイズ R = 64(64 ms 更新周期)とすることで、手指の素早い遷移相(Transient Phase)と非手指動作(NMM)に伴う等尺性収縮(Isometric Contraction)の双方をリアルタイムに捕捉します。

2. パラメータ・構成仕様(8-Channel sEMG Biquad IIR & 256-Point STFT Exact Parameter Table) East Japan (50Hz) & West Japan / Takatsuki (60Hz)
Parameter / StageSymbol / FormulaNumerical Value (f_s = 1000Hz)Bio-Signal Role
60Hz Notch (West Japan)(b0, b1, b2, a1, a2) at Q=30b0=0.9939, b1=-1.8476, a2=0.9879Suppresses Kansai 60Hz power-line hum > 40dB
50Hz Notch (East Japan)(b0, b1, b2, a1, a2) at Q=30b0=0.9949, b1=-1.8924, a2=0.9898Suppresses Kanto 50Hz power-line hum > 40dB
High-Pass Drift Filter2nd-Order Butterworth f_c = 20HzAttenuates 0..15Hz cable swayEliminates arm motion baseline wander
STFT Window SizeN = 256, R = 64 (75% overlap)Delta_f = 3.90625 Hz / binCaptures motor unit firing spectrum (Bins 5..115)
Hanning Sidelobe Roll-offFirst sidelobe -31.5 dB-18 dB/octave decayPrevents spectral leakage across adjacent bins
NMM Tension IndexCo-contraction Ratio (Flexor/Extensor)8-Channel RMS + WL VectorDistinguishes interrogative/emphatic JSL markers
3. 実装コード・設定仕様(src/dsp/semg_8ch_biquad_stft.rs)
Rust Edition 2024 (#![no_std] 8ch Biquad DF-II Transposed & Feature Extractor)
#![no_std]
#![forbid(unsafe_code)]

pub const SEMG_CHANNELS: usize = 8;
pub const STFT_WINDOW_LEN: usize = 256;

/// Normalized Biquad IIR filter coefficients (a0 normalized to 1.0).
#[derive(Clone, Copy, Debug)]
pub struct BiquadCoeffs {
    pub b0: f32,
    pub b1: f32,
    pub b2: f32,
    pub a1: f32,
    pub a2: f32,
}

impl BiquadCoeffs {
    /// Precomputed 60.0 Hz Notch Filter at f_s = 1000.0 Hz, Q = 30.0 (West Japan / Takatsuki)
    pub const NOTCH_60HZ_FS1000_Q30: Self = Self {
        b0: 0.993_912_4,
        b1: -1.847_590_6,
        b2: 0.993_912_4,
        a1: -1.847_590_6,
        a2: 0.987_824_8,
    };

    /// Precomputed 50.0 Hz Notch Filter at f_s = 1000.0 Hz, Q = 30.0 (East Japan)
    pub const NOTCH_50HZ_FS1000_Q30: Self = Self {
        b0: 0.994_885_1,
        b1: -1.892_384_5,
        b2: 0.994_885_1,
        a1: -1.892_384_5,
        a2: 0.989_770_2,
    };
}

/// Direct Form II Transposed state registers for 8 synchronous sEMG channels.
#[derive(Clone, Copy, Debug)]
pub struct MultiChannelBiquad {
    coeffs: BiquadCoeffs,
    w1: [f32; SEMG_CHANNELS],
    w2: [f32; SEMG_CHANNELS],
}

/// Real-time extracted feature frame for Sign Language Handshape & NMM tension inference.
#[derive(Clone, Copy, Debug)]
pub struct SemgFeatureFrame {
    pub mean_abs_value: [f32; SEMG_CHANNELS],
    pub waveform_length: [f32; SEMG_CHANNELS],
    pub zero_crossings: [u16; SEMG_CHANNELS],
    pub isometric_co_contraction: f32,
}

impl MultiChannelBiquad {
    pub const fn new(coeffs: BiquadCoeffs) -> Self {
        Self {
            coeffs,
            w1: [0.0; SEMG_CHANNELS],
            w2: [0.0; SEMG_CHANNELS],
        }
    }

    /// Processes a single 8-channel sample vector `x[0..8]` in O(1) time using DF-II Transposed.
    #[inline]
    pub fn process_sample_8ch(&mut self, input: &[f32; SEMG_CHANNELS]) -> [f32; SEMG_CHANNELS] {
        let mut out = [0.0f32; SEMG_CHANNELS];
        let mut ch = 0;
        while ch < SEMG_CHANNELS {
            let x = input[ch];
            let y = self.coeffs.b0 * x + self.w1[ch];
            self.w1[ch] = self.coeffs.b1 * x - self.coeffs.a1 * y + self.w2[ch];
            self.w2[ch] = self.coeffs.b2 * x - self.coeffs.a2 * y;
            out[ch] = y;
            ch += 1;
        }
        out
    }
}

/// Applies a 256-point window and extracts MAV, Waveform Length (WL), Zero Crossings (ZC),
/// and antagonist co-contraction index for NMM grammatical intensity estimation.
pub fn extract_window_features_256(
    filtered_window: &[[f32; SEMG_CHANNELS]; STFT_WINDOW_LEN],
    hanning_weights: &[f32; STFT_WINDOW_LEN],
    zc_deadzone_mv: f32,
) -> SemgFeatureFrame {
    let mut mav = [0.0f32; SEMG_CHANNELS];
    let mut wl = [0.0f32; SEMG_CHANNELS];
    let mut zc = [0u16; SEMG_CHANNELS];

    for n in 0..STFT_WINDOW_LEN {
        let w = hanning_weights[n];
        for ch in 0..SEMG_CHANNELS {
            let s_curr = filtered_window[n][ch] * w;
            let abs_s = if s_curr < 0.0 { -s_curr } else { s_curr };
            mav[ch] += abs_s;

            if n > 0 {
                let s_prev = filtered_window[n - 1][ch] * hanning_weights[n - 1];
                let diff = s_curr - s_prev;
                wl[ch] += if diff < 0.0 { -diff } else { diff };

                let sign_change = (s_curr > 0.0 && s_prev < 0.0) || (s_curr < 0.0 && s_prev > 0.0);
                let amp_diff = if diff < 0.0 { -diff } else { diff };
                if sign_change && amp_diff >= zc_deadzone_mv {
                    zc[ch] += 1;
                }
            }
        }
    }

    let inv_n = 1.0 / (STFT_WINDOW_LEN as f32);
    let mut flexor_sum = 0.0f32;
    let mut extensor_sum = 0.0f32;
    for ch in 0..SEMG_CHANNELS {
        mav[ch] *= inv_n;
        if ch < 4 {
            flexor_sum += mav[ch];
        } else {
            extensor_sum += mav[ch];
        }
    }

    let denom = flexor_sum + extensor_sum + 1e-6;
    let min_group = if flexor_sum < extensor_sum { flexor_sum } else { extensor_sum };
    let isometric_co_contraction = (2.0 * min_group) / denom;

    SemgFeatureFrame {
        mean_abs_value: mav,
        waveform_length: wl,
        zero_crossings: zc,
        isometric_co_contraction,
    }
}
ご質問・公的制度の活用に関するお問い合わせ窓口

掲載資料に関するご質問・公的制度活用のご案内

本ページの図解や解説内容に関するご質問、経済産業省「SCS評価制度」やIPA「SECURITY ACTION・サイバーセキュリティお助け隊サービス」等の公的制度の確認方法について、落ち着いた参考窓口としてご案内しております。売り込みや営業連絡は一切行いませんので、社内勉強会やご家庭での確認資料としてご自由にご活用ください。

図解・ビジュアルの拡大表示

図表内のテキストもそのまま選択・検索可能です(ベクターSVG描画) 枠外クリックまたは ESC キーで閉じます