中古rTMSデバイスと40HzライトとAlpha-Stim AID(tDCS)とMuse2(EEG)の実践記
はじめに
現代社会において、ストレスや精神的な疲労は多くの人々が直面する課題となっています。
そんな中、rTMS(反復経頭蓋磁気刺激)という治療法が注目を集めています。
しかし、その高額な自費治療の費用や保険適用のハードルから、誰もが簡単にアクセスできるものではありません。
本記事では、ADHDグレーゾーンにいる私自身がrTMSデバイスの中古市場での取得から輸入手続き、そのほかに試したAlpha-Stim AIDや40Hzライトの自作・実践までを綴ります。
数々の失敗や試行錯誤を経て得た知見を共有し、同じような関心を持つ方々への一助となれば幸いです。
第1章:rTMSの世界に足を踏み入れる
1-1. rTMSとは何か
rTMSは、頭部に磁気刺激を与えることで脳の活動を調節する非侵襲的な治療法です。主にうつ病や神経疾患の治療に用いられています。しかし、その治療費は高額で、専用のクリニックでしか受けられないのが現状です。
1-2. 保険適用の壁
調査を進める中で、「NeuroStar」というデバイスが保険適用で利用できることを知りました。しかし、以下の課題が立ちはだかりました。
入院が必要:通院ではなく入院措置が求められる。
施設が限られている:全国でも利用可能なクリニックは多くはない。
費用負担:保険適用でも自己負担額が大きい。
これらの要因から、手軽に試すことは難しいと感じました。
1-3. 高額な自費治療の壁
自由診療となるとおおむね1回あたり5000円から10000円、それを30回行うため15万円から30万円の出費となります。
一度の治療で寛解すればいいですが、さらに追加の治療が必要になったり、定期的に治療が必要になるかたもいらっしゃるようです。
第2章:中古rTMSデバイスを探す
2-1. 中古市場の可能性
新たな解決策を求めて、海外の中古市場に目を向けました。そこで見つけたのが、eBayなどで販売されている中古のrTMSデバイスです。
Magstim 200^2:臨床でも使用される信頼性の高いモデル。
NeuroStar:前述の保険適用ができる高額モデルが治療費と同じ程度の金額で出品されている。
これらが数千ドル(約数十万円)で取引されていることを知り、手が届くかもしれないと考え、実際にMagstimを落札しました。
ADHDに対する効果を示すエビデンスは十分ではなく、二次症状である鬱に対しては、右脳前頭前野への低頻度刺激(1ヘルツ)がエビデンスがあり有効とのことでこのモデルの落札を決意しました。
当時のUSDJPYのレートは155円程度、税金、輸送量、関税を加えると80万円近く投資となりました。
3回分の治療費と考えたら高いでしょうか?安いでしょうか?
記事執筆中に気づきましたがヤフオクでも部品取り用の機器が販売されています。(本来は医療品の出品は禁止なので規約違反ですね。)
第3章:輸入手続きの壁を越える
3-1. 法的手続きの確認
医療機器を輸入するには、法的手続きが求められます。
薬機法の遵守:個人輸入でも規制対象となる。
薬監証明の取得:地方厚生局での手続きが必要。
3-2. 薬監証明の取得手順
必要書類の準備: 以下3点は必須です。
製品仕様書
購入証明書(インボイスや注文書)
医師より発行された診断書
申請手続き:
地方厚生局にオンラインで上記3つの書類を提出。
審査を経て、証明書を発行。
輸送と通関:
輸入確認申請書を添付して輸入手続きを進める。
3-3. 実際のMagstimの輸入手続き体験
3-3-1.製品仕様書
ミユキ技研という会社が扱っており、そこでカタログの入手が可能です。
3-3-2. 診断書
精神科の先生に正直に事情を話して協力を得ましょう。
診断書をアップロードするステップがあります。
3-3-2. 医療品等輸入確認システム
デジタル庁の頑張りのためか、オンラインで完結するシステムが提供されています。
画面遷移をすべてキャプチャしましたので、何をどう入力するのか確認してください。(ユーザー登録は一回きりなので、残念ながらありません)
第4章:40Hzライトの自作と実験
90%オフでお得だからといっても、高い状況には変わりがありません。
そこで脳を活性化させる光デバイスとリラックスさせる微電流デバイス(tDCS)も試してみました。
4-1. 40Hzライトとは
40Hzの光刺激は、脳のガンマ波(γ波)を誘発するとされ、アルツハイマー病の研究などで注目されています。
痴呆対策にもいいですが、若いうちから脳を活性化させていきましょう。
4-2. 自作への挑戦
初期の試行錯誤
555タイマーICを使用して回路を組む。
周波数の安定化が難しく、微妙なズレが生じる結果となった。
555タイマーICを使って周波数を設定する場合、次の式を使います:
R1 = 1kΩ
R2= 1.3kΩ
C1 = 10μF
Raspberry Pi Picoでの解決
Picoに搭載されているハードウェアクロックは高精度のパルス生成が可能なため555タイマーはあきらめ乗り換えました
マイクロコントローラを活用して正確な制御を実現
import machine
import time
# LEDのピンを設定 (例: GPIO 15)
led = machine.Pin(15, machine.Pin.OUT)
# 40Hzに対応するための待機時間 (1/40 = 0.025秒の半分 = 0.0125秒)
delay = 0.0125
# 無限ループでLEDを点滅させる
while True:
led.on() # LEDをON
time.sleep(delay) # 0.0125秒待機
led.off() # LEDをOFF
time.sleep(delay) # 0.0125秒待機
オシロスコープで波形を確認し、正確な40Hzを実現。
4-3. Processing(脳波波形描画ツール)
Processingでは、oscP5ライブラリを使用してOSCメッセージの送受信を行い、MinimライブラリやFFTクラスを使用して周波数帯域の抽出を行うことができます。以下に、これらの操作を実現するためのサンプルコードを提供しますので、まずはダウンロードをしてインストールしてください。
必要なライブラリのインストール
Processingを起動します。
メニューバーから スケッチ > ライブラリをインポート > ライブラリを追加 を選択します。
ライブラリマネージャが開いたら、以下のライブラリを検索してインストールします:
oscP5
Minim
コードの主な機能
OSC通信:
受信: ポート4545でOSCメッセージを受信し、リアルタイムデータを取得します。
送信: 受信したデータを計算した後、ポート4546に送信します(/out/alphaと/out/gammaのアドレス)。
リアルタイム描画:
グラフにAlpha波とGamma波の平均値をリアルタイムでプロットします。
グラフのスケールは固定で設定されており、過去データとの比較が可能です。
15分間のGamma波平均の計算と描画:
Gamma波の15分間の平均値を水平線として描画します。
水平線に対応する数値がグラフの上部に表示されます。
import oscP5.*;
import netP5.*;
import ddf.minim.*;
import ddf.minim.analysis.*;
import java.util.Collections; // 追加: 最小値と最大値取得のため
OscP5 oscP5;
Minim minim;
// OSC送信用の送信先アドレス
NetAddress sendAddress;
// 定数設定
final int RECEIVE_PORT = 4545;
final int SEND_PORT = 4546; // 送信ポート
final String SEND_IP = "127.0.0.1"; // 送信先IP
final int SAMPLING_RATE = 256; // Hz
final int BUFFER_SIZE = SAMPLING_RATE; // 1秒分のデータ
final int DURATION_SECONDS = 180; // 3分
final int MAX_AVERAGE_POINTS = DURATION_SECONDS; // 1秒ごとの平均を180秒保持
// 15分間の平均を保持するための設定
final int DURATION_SECONDS_15 = 900; // 15分
final int MAX_AVERAGE_POINTS_15 = DURATION_SECONDS_15; // 1秒ごとの平均を900秒保持
// Y軸の固定スケール
final float GRAPH_Y_MIN = 0; // 必要に応じて調整
final float GRAPH_Y_MAX = 1.5; // 必要に応じて調整
// チャンネル数
final int NUM_CHANNELS = 4;
// チャンネル名
String[] channelNames = {"/muse/eeg/tp9", "/muse/eeg/af7", "/muse/eeg/af8", "/muse/eeg/tp10"};
// データ保持用リスト
ArrayList<Float>[] dataBuffers = new ArrayList[NUM_CHANNELS];
// FFTオブジェクト
FFT[] fftAlpha = new FFT[NUM_CHANNELS];
FFT[] fftGamma = new FFT[NUM_CHANNELS];
// 最新のパワー値保持用
float[] latestAlphaPowers = new float[NUM_CHANNELS];
float[] latestGammaPowers = new float[NUM_CHANNELS];
// 平均値保持用リスト
ArrayList<Float> averageAlphaList = new ArrayList<Float>();
ArrayList<Float> averageGammaList = new ArrayList<Float>();
// 15分間のGamma平均値保持用リスト
ArrayList<Float> averageGamma15List = new ArrayList<Float>();
// プロット設定(動的に設定)
float graphX, graphY, graphWidth, graphHeight;
// 色設定(淡色)
color alphaColor = color(173, 216, 230); // 淡い水色
color gammaColor = color(255, 182, 193); // 淡いピンク色
color axisColor = color(0); // 黒色
color avgGammaColor = color(0, 0, 0); // 15分平均の線の色(黒色)
// タイマー設定
int lastAverageTime = 0;
// データ同期フラグ
boolean[] channelReady = new boolean[NUM_CHANNELS];
void settings() {
size(1400, 700, P2D); // 初期ウィンドウサイズを設定
}
void setup() {
surface.setResizable(true); // ウィンドウのリサイズを可能にする
background(255);
// Minimのセットアップ
minim = new Minim(this);
// OSC受信のセットアップ
oscP5 = new OscP5(this, RECEIVE_PORT);
// OSC送信の送信先アドレスを設定
sendAddress = new NetAddress(SEND_IP, SEND_PORT);
// データ初期化
for(int i=0; i<NUM_CHANNELS; i++) {
dataBuffers[i] = new ArrayList<Float>();
// FFTの初期化
fftAlpha[i] = new FFT(BUFFER_SIZE, SAMPLING_RATE);
fftAlpha[i].window(FFT.HAMMING);
fftGamma[i] = new FFT(BUFFER_SIZE, SAMPLING_RATE);
fftGamma[i].window(FFT.HAMMING);
latestAlphaPowers[i] = 0;
latestGammaPowers[i] = 0;
channelReady[i] = false;
}
// フレームレート設定(フリッカー軽減のため低下)
frameRate(15);
// テキスト設定
textSize(16);
textAlign(CENTER, CENTER);
}
void draw() {
background(255); // 背景を白にリセット
// グラフの位置とサイズを動的に設定
setGraphDimensions();
// 軸の描画
drawAxes();
// データの描画
drawData();
// インジケータの描画(コメントアウト)
// drawIndicator();
// 平均値の計算タイミング
int currentTime = millis();
if(currentTime - lastAverageTime >= 1000) { // 1秒ごと
calculateAndStoreAverages();
lastAverageTime = currentTime;
}
}
void setGraphDimensions() {
// ウィンドウサイズに応じてグラフの位置とサイズを設定
graphX = width * 0.05; // 左から5%
graphY = height * 0.1; // 上から10%
graphWidth = width * 0.9; // 幅の90%(右端まで拡張)
graphHeight = height * 0.8; // 高さの80%
}
void drawAxes() {
stroke(axisColor);
strokeWeight(1);
// X軸
line(graphX, graphY + graphHeight, graphX + graphWidth, graphY + graphHeight);
// Y軸
line(graphX, graphY, graphX, graphY + graphHeight);
// ラベル
fill(0);
noStroke();
textAlign(CENTER, CENTER);
text("Time (3 minutes)", graphX + graphWidth / 2, graphY + graphHeight + 40);
pushMatrix();
translate(graphX - 60, graphY + graphHeight / 2);
rotate(-PI / 2);
text("Amplitude", 0, 0);
popMatrix();
// 時間目盛り(1分ごと)
textAlign(CENTER, CENTER);
for(int i=0; i<=3; i++) {
float x = map(i, 0, 3, graphX, graphX + graphWidth);
stroke(axisColor);
line(x, graphY + graphHeight, x, graphY + graphHeight + 10);
noStroke();
text(i + "m", x, graphY + graphHeight + 20);
}
}
void drawData() {
// Y軸のスケーリングを固定
float yMin = GRAPH_Y_MIN;
float yMax = GRAPH_Y_MAX;
// ガンマ波の描画(背景として)
noStroke();
fill(gammaColor, 100); // 透明度を調整
beginShape();
vertex(graphX, graphY + graphHeight); // 左下
for(int i=0; i<averageGammaList.size(); i++) {
float x = map(i, max(0, averageGammaList.size() - MAX_AVERAGE_POINTS), averageGammaList.size(), graphX, graphX + graphWidth);
float y = map(averageGammaList.get(i), yMin, yMax, graphY + graphHeight, graphY);
vertex(x, y);
}
vertex(graphX + graphWidth, graphY + graphHeight); // 右下
endShape(CLOSE);
// アルファ波の描画(ガンマ波の上に)
noStroke();
fill(alphaColor, 100); // 透明度を調整
beginShape();
vertex(graphX, graphY + graphHeight); // 左下
for(int i=0; i<averageAlphaList.size(); i++) {
float x = map(i, max(0, averageAlphaList.size() - MAX_AVERAGE_POINTS), averageAlphaList.size(), graphX, graphX + graphWidth);
float y = map(averageAlphaList.get(i), yMin, yMax, graphY + graphHeight, graphY);
vertex(x, y);
}
vertex(graphX + graphWidth, graphY + graphHeight); // 右下
endShape(CLOSE);
// 15分間のGamma平均値の描画
if(!averageGamma15List.isEmpty()) {
float sum = 0;
for(Float val : averageGamma15List) {
sum += val;
}
float avgGamma15 = sum / averageGamma15List.size();
stroke(avgGammaColor);
strokeWeight(2);
line(graphX, map(avgGamma15, yMin, yMax, graphY + graphHeight, graphY), graphX + graphWidth, map(avgGamma15, yMin, yMax, graphY + graphHeight, graphY));
noStroke();
fill(avgGammaColor);
textAlign(LEFT, BOTTOM);
text("15-min Gamma Avg: " + nf(avgGamma15, 1, 2), graphX, graphY - 10);
}
}
void calculateAndStoreAverages() {
// 各チャンネルの最新のパワーを使用して平均を計算
float sumAlpha = 0;
float sumGamma = 0;
int countAlpha = 0;
int countGamma = 0;
for(int i=0; i<NUM_CHANNELS; i++) {
sumAlpha += latestAlphaPowers[i];
sumGamma += latestGammaPowers[i];
countAlpha++;
countGamma++;
}
float avgAlpha = countAlpha > 0 ? sumAlpha / countAlpha : 0;
float avgGamma = countGamma > 0 ? sumGamma / countGamma : 0;
// リストに追加
averageAlphaList.add(avgAlpha);
averageGammaList.add(avgGamma);
// リストサイズを維持
if(averageAlphaList.size() > MAX_AVERAGE_POINTS) {
averageAlphaList.remove(0);
}
if(averageGammaList.size() > MAX_AVERAGE_POINTS) {
averageGammaList.remove(0);
}
// 15分間のGamma平均値を計算・追加
averageGamma15List.add(avgGamma);
if(averageGamma15List.size() > MAX_AVERAGE_POINTS_15) {
averageGamma15List.remove(0);
}
// OSCメッセージの送信
sendOscMessage("/out/alpha", avgAlpha);
sendOscMessage("/out/gamma", avgGamma);
}
void sendOscMessage(String address, float value) {
OscMessage msg = new OscMessage(address);
msg.add(value);
oscP5.send(msg, sendAddress);
// デバッグ用: 送信内容をコンソールに表示
println("Sent OSC Message to " + SEND_IP + ":" + SEND_PORT + " - " + address + ": " + value);
}
void oscEvent(OscMessage theOscMessage) {
String addr = theOscMessage.addrPattern();
// メッセージアドレスの解析
// 例: /muse/eeg/tp9, /muse/eeg/af7, /muse/eeg/af8, /muse/eeg/tp10
for(int i=0; i<NUM_CHANNELS; i++) {
if(addr.equals(channelNames[i])) {
if(theOscMessage.checkTypetag("f")) { // フロート型を期待
float value = theOscMessage.get(0).floatValue();
// println("Received " + channelNames[i] + ": " + value); // コンソール出力を停止
// データを追加
dataBuffers[i].add(value);
// バッファサイズを超えたら古いデータを削除
if(dataBuffers[i].size() > BUFFER_SIZE) {
dataBuffers[i].remove(0);
}
// バッファがいっぱいになったらFFTを実行
if(dataBuffers[i].size() == BUFFER_SIZE) {
float[] buffer = new float[BUFFER_SIZE];
for(int j=0; j<BUFFER_SIZE; j++) {
buffer[j] = dataBuffers[i].get(j);
}
// FFTの実行(アルファー帯域)
fftAlpha[i].forward(buffer);
float alphaPower = getBandPower(fftAlpha[i], 8, 12);
// FFTの実行(ガンマ帯域)
fftGamma[i].forward(buffer);
float gammaPower = getBandPower(fftGamma[i], 30, 50);
latestAlphaPowers[i] = alphaPower;
latestGammaPowers[i] = gammaPower;
// デバッグ用: FFT結果を確認
// println("Channel " + i + " - Alpha Power: " + alphaPower + ", Gamma Power: " + gammaPower);
}
} else {
// デバッグ用: 不正な型のメッセージを確認
// println("Received non-float message on " + addr);
}
break; // 一致したらループを抜ける
}
}
}
// 指定周波数帯域のパワーを計算
float getBandPower(FFT fft, float freqStart, float freqEnd) {
float power = 0;
for(int i=0; i<fft.specSize(); i++) {
float freq = fft.getBand(i) * (SAMPLING_RATE / BUFFER_SIZE);
if(freq >= freqStart && freq <= freqEnd) {
power += fft.getBand(i);
}
}
return power;
}
void stop() {
oscP5.stop();
minim.stop();
super.stop();
}
4-5. BluetoothでMuse2とWindowsを接続する(Bluemuse)
BlueMuseのインストール方法
BlueMuseは、WindowsでMuseデバイスを簡単に利用できるアプリケーションです。このガイドでは、PowerShellを利用したインストール方法を詳しく解説します。
必要要件
BlueMuseをインストールするには、以下の条件を満たしている必要があります:
Windows 10 Fall 2017 Creators Update以降
(バージョン10.0.15063、Windows 10 (1703)以上)
インストール手順
1. BlueMuseのダウンロード
BlueMuseのGitHubページ にアクセスします。
最新バージョンのリリースページに移動し、アプリケーションファイルをダウンロードします。
ダウンロードしたZIPファイルを解凍します。
2. 自動インストール(推奨)
解凍したフォルダに移動します。
フォルダ内にあるInstallBlueMuse.ps1ファイルを探します。
次のいずれかの方法でスクリプトを実行します:
方法1: InstallBlueMuse.ps1を右クリックし、「PowerShellで実行」を選択。
方法2: PowerShellターミナルを開き、以下のコマンドを入力して実行:
powershell
3. インストールのプロンプトに従う
PowerShellスクリプトが以下の内容を自動的に処理します:
セキュリティ証明書のインストール
BlueMuseが安全に動作するための証明書をインストールします。依存関係のインストール
必要なライブラリやコンポーネントを自動的にダウンロードして設定します。BlueMuseのインストール
アプリケーション本体をシステムにインストールします。
プロンプトに従うだけで、簡単にインストールが完了します。
あとは起動するだけです
start bluemuse:
4-6. BluemuseからOSCでデータを送信する
Muse-oscのインストールと使用方法
muse-oscは、MuseヘッドバンドのデータをOSC形式で出力し、Neuromore Studioや他のNeurofeedbackシステムと連携するためのツールです。
今回はProcessingを使用します。
必要な環境
以下が必要です:
Python 3.7以上
Museヘッドバンド(Muse 2またはMuse S推奨)
Bluetoothが有効なPCまたはデバイス
インストール手順
1. Python環境の準備
Pythonのインストール
Pythonがインストールされていない場合は、Python公式サイトから最新版をダウンロードし、インストールします。仮想環境の作成(推奨)
仮想環境を使用することで、依存関係を他のプロジェクトと分離できます。
python -m venv muse-env
source muse-env/bin/activate # macOS/Linux
muse-env\Scripts\activate # Windows
2. muse-oscのインストール
リポジトリのクローンまたはダウンロード
muse-oscのGitHubリポジトリからプロジェクトをクローンまたはZIPファイルをダウンロードします。
git clone https://github.com/alexandrebarachant/muse-osc.git
cd muse-osc
必要なライブラリのインストール
必要なライブラリをインストールします。
pip install -r requirements.txt
3. Museデバイスの接続とOSCストリームの開始
BlueMuseを使用してBluetooth接続を確立
Museヘッドバンドをペアリングモードにします(電源をオンにして点滅する青いランプを確認)。
BlueMuseを使用して、PCとMuseデバイスを接続します。
muse-oscの起動
以下のコマンドを実行して、OSCストリームを開始します。
python -m muse_osc
4-7. 実験結果
EEGデバイス(Muse 2)を使用して脳波を計測。
ガンマ波の増加が観測され、一定の効果を確認。
第5章:tDCSでアルファ波を探る
5-1. tDCSとは
tDCSは、頭皮に微弱な電流を流すことで脳の活動を調節する方法です。
アルファ波(8~12Hz)が発生し、リラックスができます。
5-2. 実践の流れ
市販のtDCSデバイスは安全性を最優先に、信頼できるメーカーを選ぶ。Alpha-Stim AID はFDAの承認が取れています。
ほかにもBrainDriverというのがあります。
実験手順
電極の配置:両方の耳たぶに電極クリップを装着。
電流の設定:0.5~1mAの微弱な電流を設定。
セッションの実施:40分間の刺激を行う。
5-3. 脳波の解析
EEGデバイスで脳波を記録。
結果:アルファ波の増加傾向が見られ、リラクゼーション効果を実感。
最終章:今後の展望
6-1. デバイスの改良と新たな挑戦
rTMSとtDCSの組み合わせ:相乗効果の検証。
データ収集の継続:長期的な効果の観察。
終わりに
今回の挑戦を通じて、個人の力でも技術にアクセスし、新たな可能性を探ることができると実感しました。
しかし、それと同時に法令遵守や安全性の確保の重要性を痛感しました。
もっとも肝を冷やしたのが通関申請です。
たとえ日本国内で流通しているマシンでも通関申請が間違ったり、担当者に拒否されたら投資が無駄になるからです。
これからも試行錯誤を続けながら、得られた知見を共有していきたいと思います。同じ志を持つ方々とともに、健全な技術の発展に寄与できれば幸いです。
最後の最後にNeuroStarの購入を検討されている方向けのアドバイスがあります。
とても重要な情報ですので、内容を有料にしています。
設定価格以上の価値がある情報ですので、NeuroStarの購入を真剣に考えている方はぜひご確認ください。
それ以外の方は見る必要のない情報ですが、もしこの記事がいいと思ったら見てくれると嬉しいです。
ここから先は
¥ 300
この記事が気に入ったらチップで応援してみませんか?