筋肉の電気信号・筋電位の識別 Part 2

前回は筋電位の計測し,どういった信号なのかを確認しました. 今回は計測結果を元にchainerを用いてニューラルネットワークで手の姿勢を識別しました.

目次

はじめに

前回の計測では筋電位センサでじゃんけんの時の筋電位を計測しました.
今回は計測した筋電位から手の姿勢を推定できるか,chainerを使って検証してみます.

筋電図の特徴量

こちらの論文では8つの手動作姿勢の識別にどの特徴量を用いるのが良いか検証しています.
https://www.jstage.jst.go.jp/article/kikaic/79/808/79_4746/_pdf
検証している特徴量は以下の通りです.
 1.生データ
 2.積分筋電位(IEMG)
 3.最大成分周波数(FFT Peek)
 4.パワースペクトル
 5.立ち上がり筋電位
 6.ウェーブレット係数
SVMを用いて識別をしていますが,IEMGを特徴量として用いた時が最も高い識別率を示しています.
この記事ではパワースペクトルを特徴量として識別してみます.

データセットの作成

計測条件と計測箇所は前回と同様です.
FFTの条件
・サンプリング数 256
・オーバーラップ数 64
・窓関数 ハミング窓
3つのセンサのパワースペクトルから成るベクトルと姿勢ラベルを1セットとすると合計で225セット.
データセットの作成のコーディングに手間を取ったのでプログラムを載せておきます.
    # データセット 学習データ(パワースペクトル)*センサ数+ラベル(姿勢)
    emg_dataset = np.empty((SAMPLING_N // 2 + 1) * SENSOR_NUM + 1)

    for posture in range(POSTURE_NUM):
        pyplot.figure()
        data_csv = pd.read_csv("emg" + str(posture) + ".csv", header=None)
        # 時刻ごとのFFT
        index = 0
        while index + SAMPLING_N < data_csv.shape[0]:
            amp_array = np.empty(0)
            # センサごとのFFT
            for i in range(SENSOR_NUM):
                emg = data_csv[i].values[index: index + SAMPLING_N]
                # フィルター処理
                emg = signal.detrend(emg)
                emg = np.convolve(emg, np.ones(10) / 10.0, mode='same')
                # 窓関数
                window = np.hamming(SAMPLING_N)
                f = np.fft.fft(emg * window)
                amp = np.abs(f)
                amp = amp[0: SAMPLING_N // 2 + 1]
                amp_array = np.append(amp_array, amp)
            # ラベルとして姿勢を登録
            label = posture
            amp_array = np.append(amp_array, label)
            emg_dataset = np.vstack((emg_dataset, amp_array))
            index += SAMPLING_N // 4

    emg_dataset = np.delete(emg_dataset, 0, 0)
    # 配列並び替え
    np.random.shuffle(emg_dataset)

    train_data = emg_dataset[:, 0: emg_dataset.shape[1] - 1].astype(dtype=np.float32)
    label_data = emg_dataset[:, emg_dataset.shape[1] - 1: emg_dataset.shape[1]].T.astype(dtype=np.int32)
    label_data = label_data[0]

    # 学習データの教師データとテスト用データに分ける
    threshold = np.int32(emg_dataset.shape[0] * 9 / 10)
    train = tuple_dataset.TupleDataset(train_data[0:threshold], label_data[0:threshold])
    test = tuple_dataset.TupleDataset(train_data[threshold:], label_data[threshold:])
一次元ベクトルのデータセット.py
訓練データとラベルは別に扱いますが,データをランダムに扱うために
まずは学習データの最後にラベルを追加して,シャッフルし,その後分離しています.

ニューラルネットワークの作成

使用したニューラルネットワークは以下の通り.
入力層 129x3次元
中間層 512
出力層 3次元
重み決定法 確率的勾配法
学習回数 200

結果!

NNの損失

学習するに連れて学習データ,テストデータ共に誤差が小さくなっていることが確認できます.
ちなみに識別率は100%を達成しました.

まとめ

手の姿勢がグー,チョキ,パーの時の筋電位を計測して,得られた筋電図から手の姿勢を3層ニューラルネットワークで識別できることが確認できました.
センサーを付ける位置や筋肉の量,筋疲労,皮膚の状態によって結果が変化するので,
ぜひ皆さんも挑戦してみてください.