ラズパイで心電図を作ってみた

はじめに

Raspberry pi(ラズパイ)を使って職場の環境モニタリングを行っていますが、もっと別のことにもラズパイを使えないかということで心電図モニタを作ってみることにしました。

概ねArduinoを使った既報と類似していますが、以下の点が新しい視点となっています。

  • Raspberry Piから値を取得するためにADCを導入
  • processingでssh接続のシリアルプロッタを作成

f:id:akcharine:20190421010732p:plain

ECGとパルスオキシメーター

 今回、作ったのは心電図(ECG: electrocardiogram)です。ラズパイでの紹介記事が多いパルスオキシメータとは異なりますので注意して下さい。心拍センサとして販売されているラズパイ部品の多くはパルスオキシメーターです。

  • ECG: 心臓の電気的活動を捉えるもの。電極を体に付ける。検診で手足や胸にヒヤッとやつを付ける。
  • パルスオキシメーター: 動脈血酸素飽和度を捉えるもの。指にクリップを挟む。

注意

  • 本記事で紹介したデバイスを医療目的で使用しないで下さい。
  • 心電図による診断は、薬機法で認められた医療機器を用いて医師により行われるものです。

仕様

  • 心電図
    • 1つの誘導だけ測定できる
    • 時間分解能: 0.01 s
  • 出力
    • バイナリファイル
    • シリアルプロッタ(processingで作成)

f:id:akcharine:20190427215525j:plain

コード

ソースコードgithubで公開しています。

akchan/ecg_plotter

材料

接続

下図の要領でラズパイとデバイスを接続しました。

f:id:akcharine:20190427224735p:plain

今回使用した心電図センサ(AD8232)はアナログ出力で、そのままではラズパイで読めないため、間にADC(ADS1015)をおいて値を取得することにしました。

状態表示用の有機ELモニタは、ラズパイ-ADC間の通信品質を保つため、I2CではなくSPI接続のものを使用しています。ピンアサインはpythonライブラリ luma.oledのリファレンスを参照しました。

Raspberry Pi Zeroのセットアップ

次の記事を参考にしてmacbook proからusb接続でセットアップをしました。初期設定後はAPに接続させてwifiでアクセスできるようにしています。

qiita.com

RTC (DS3231)セットアップ

モバイルでも利用できるよう、RTCのセットアップを行います。

まずはI2C接続を有効にしてモジュールを読み込みます。

# まずI2C接続を有効化する。
$ sudo raspi-config
# 以下のように進む。
# '5 Interfacing Options' -> 'P5 I2C' -> 'Yes'

# モジュールを読み込むようにする。
$ sudo vi /boot/config.txt
# 以下を追加
dtoverlay=i2c-rtc,ds3231

# 再起動
$ sudo reboot

# アドレス68がUUになっていることを確認
$ i2cdetect -y 1

# モジュールが読み込まれていることを確認する。
$ modprobe -c|grep 3231

# 時刻が表示されるのを確認する。
$ sudo hwclock -r

次にRTCが内蔵されていないraspberry piでRTC代わりにインストールされているfake-hwclockをアンインストールします。

$ sudo apt purge fake-hwclock

RTCを日本標準時に合わせるため、NTPクライアントとしてchronyをインストール。

$ sudo apt install chrony

# 参照先ntpサーバを追加
$ sudo vim /etc/chrony/chrony.conf
#以下を追加
pool ntp.nict.jp
pool ntp.jst.mfeed.ad.jp

# 同期状況を確認
$ chronyc sources

心電図について

値の取得

心電図センサからの出力はアナログなのでI2C接続のADC(ADS1015, adafruit)を使って値を取得しました。

ADCからの値取得はadafruitが提供しているpythonモジュールを使用しました。

adafruit/Adafruit_Python_ADS1x15: Python code to use the ADS1015 and ADS1115 analog to digital converters with a Raspberry Pi or BeagleBone black.

GAINはデフォルトのままで問題なく動作しました。

時間分解能

通常、心電図の記録用紙は0.04秒ごとに目盛りが刻まれています。

実際に動作させてみると1回の値取得あたり約3msかかる様でした。

そこで今回はマージンを付けて、サンプリングレートは0.01秒(=10ms)になるようコードを作成しました。ADCのサンプリングレートは最も低速の128に設定しています。

電極のつなぎ方

用意した心電図ケーブルは臨床使用されている心電図ケーブルと色が異なるので注意が必要です。

  • 黒: 肢誘導の赤に相当。今回は胸骨角部に装着。
  • 青: 肢誘導の黄に相当。今回は第5肋間鎖骨中線(12誘導の茶色[C4])に装着
  • 赤: 肢誘導の黒に相当。今回は右側側腹部に装着。

測定時の注意

楽な体勢で測定する

力が入っていると骨格筋の電位を拾ってしまいます。

新しい電極パッドを使う

電極を使い回すとパッドの性能が低下して心電図が正確に測れなくなってきます。

四肢を床から離す

理由は分かりませんが、両足を素足でフローリングに付けていると測定できませんでした。臥位以外で測定する場合は注意が必要です。今回は両足を座布団の上に置いて、椅子に座って測定しました。

シリアルプロッタを作る

表示部をどうするかが一番の問題でした。

Arduinoだと標準でシリアルプロッタが添付されているため心電図記録の表示が簡単に行えるのですが、ラズパイの場合は自分で用意する必要があります。Google先生に聞いてみると、matplotlibを使ったものやwebsocketを利用したものがありましたが、どれも満足のいくフレームレートが出ませんでした。

そこで今回はssh接続で取ってきた値をprocessing (java)を使って表示するシリアルプロッタを自作しました。

youtu.be

最後に

Raspberry Pi Zeroを使って心電図モニタを作りました。今回はシリアルプロッタでリアルタイム表示するまでですが、モバイルバッテリーでも動くraspberry pi zeroを使っているので日常での心電図測定にも応用できそうです。

MATLABでウィンドウ条件を変更する

MATLABでCTやMRIのウィンドウ条件を変更する話。

Image processing toolbox

画像関連の関数がパッケージになったツールボックスが用意されている。

jp.mathworks.com

DICOM画像を読み込んで表示する場合はこんな感じ。

img = dicomread('CT-MONO2-16-ankle.dcm');
f = imtool(img);
incontrast(f);

画像と輝度ヒストグラムが表示される。

輝度ヒストグラムウィンドウにウィンドウレベル(WL)/ウィンドウ幅(WW)を入力することで表示条件を調整できる。さらに「データの調整」ボタンを押せば0-1に画像をキャストできる。

対話的に作業するならこれで事足りるが、大量の画像を処理したいときには困る。

imadjust(I, [high low], [high low])

画像コントラストを調整するために、imadjust関数が用意されている。ただ、この関数は基本的に低コントラスト画像を強調するために使うことを前提としているらしく、扱える数値が0〜1の間だけという制限があってint16が使われることが多いDICOM画像とは相性が悪い。

dcmadjust(i, wl, ww)

ということで関数を書いた。

グレースケール画像とWL, WWを与えると0-1にスケーリングして返してくれる。0-1なのでそのままimwrite()で書き出せる。

function result = dcmadjust(img, wl, ww)

img = double(img);

min = double(wl - ww / 2);
max = double(wl + ww / 2);

img(img>max) = max;
img(img<min) = min;

result = (img - min * ones(size(img))) / ww;

使用例

img = dicomread('CT-MONO2-16-ankle.dcm');
imtool(img);

img_adjusted = dcmadjust(img, 1000, 2000);
imtool(img_adjusted);