カテゴリー別アーカイブ: 未分類

Fitbit+Python(1)

ここでは、Fitbitで計測されたデータをPythonで取得する方法を解説します。作業のおおまかな手順は下記の動画をご覧ください。

Anacondaのインストール
Python実行環境であるAnacondaのインストールを行う。とりあえずAnaconda3をダウンロードして道なりにインストール。Environmentから仮想環境「Fitbit」を作成し、「OpenTerminal」でターミナルを表示する。Pythonコマンドで動作を確認する。Ctrl+Zで対話モードを終了できる。インストールは、こちらのサイトが参考になる。

Fitbitの開発者向けサイトでアプリケーションを登録する
PythonからFitbitAPIを使うにはアプリの登録が必要となる。FitbitDevelopperサイトにログインして、Manage>RegisterAppの順で進み、アプリケーションを登録する。設定は以下の画像の通りにする。URL関係は全てダミーのURLで問題なく、RedirectURLは、「http://127.0.0.1:8080/」とする。ページ内で作成された「OAuth 2.0 Client ID」と「Client Secret」をPythonスクリプト中で使用することになる。
Devサイトでのアプリ作成方法

Fitbit API Python Clientのインストール
GitHub – orcasgit/python-fitbit: Fitbit API Python Client Implementationからcodeボタンを押し、Zipファイルをダウンロードし、中身をCドライブ直下に配置する(こちらのサイトが参考になる)。さらに、下記コマンドで追加パッケージをインストールする。

pip install -r requirements/base.txt
pip install cherrypy 

Pythonスクリプトでクラウド上のファイルを取得
c:\python-fitbitフォルダに下記スクリプトをfitbit01.pyという名前で保存し、実行する。Anaconda Promptから下記コマンドを打ち込む

python fitbit01.py

#fitbit01.py
import sys
import fitbit
import gather_keys_oauth2 as Oauth2
   
print('Hello FitbitAPP3') 
   
USER_ID     = "ほげ"
CLIENT_SECRET = "ほげ"
   
DATE = "2021-06-03" # 取得したい日付
   
   
server = Oauth2.OAuth2Server(USER_ID, CLIENT_SECRET)
server.browser_authorize()
ACCESS_TOKEN = str(server.fitbit.client.session.token['access_token'])
REFRESH_TOKEN = str(server.fitbit.client.session.token['refresh_token'])
   
#print(ACCESS_TOKEN) print('\n') 
#print(REFRESH_TOKEN)print('\n') 
   
"""Authorization"""
auth2_client = fitbit.Fitbit(USER_ID, CLIENT_SECRET, oauth2=True, access_token=ACCESS_TOKEN, refresh_token=REFRESH_TOKEN)
   
"""Getting data"""
#print('Getting data\n') 
#fitbit_stats = auth2_client.intraday_time_series('activities/heart', DATE, detail_level='1min')
    
##################################################
fitbit_stats = auth2_client.intraday_time_series('activities/heart', DATE, detail_level='1min')
stats = fitbit_stats['activities-heart-intraday']['dataset']
   
OUTPUT_FILE = "HR_%s.csv" % DATE
csv_file = open(OUTPUT_FILE, 'w')
for var in range(0, len(stats)):
    csv_file.write(stats[var]['time'])
    csv_file.write(",")
    csv_file.write(str(stats[var]['value']))
    csv_file.write("\n")
csv_file.close()
   
##################################################
fitbit_stats = auth2_client.intraday_time_series('activities/steps', DATE, detail_level='1min')
stats = fitbit_stats['activities-steps-intraday']['dataset']
   
OUTPUT_FILE = "STEP%s.csv" % DATE
csv_file = open(OUTPUT_FILE, 'w')
for var in range(0, len(stats)):
    csv_file.write(stats[var]['time'])
    csv_file.write(",")
    csv_file.write(str(stats[var]['value']))
    csv_file.write("\n")
csv_file.close()
   
##################################################
fitbit_stats = auth2_client.intraday_time_series('activities/calories', DATE, detail_level='1min')
stats = fitbit_stats['activities-calories-intraday']['dataset']
   
OUTPUT_FILE = "CALO%s.csv" % DATE
csv_file = open(OUTPUT_FILE, 'w')
for var in range(0, len(stats)):
    csv_file.write(stats[var]['time'])
    csv_file.write(",")
    csv_file.write(str(stats[var]['value']))
    csv_file.write("\n")
csv_file.close()

トラブルシューティング

・RedirectURLが、http://127.0.0.1:8080/で正しく動作しない場合
ポート8080をなにかのプログラムが使っている可能性がある。その場合は、RedirectURLを、「http://127.0.0.1:8088/」とし、python-fitbitフォルダ中のgather_keys_oauth2.pyの該当部分を「8088」に変更してスクリプトを実施する。

・Pythonのスクリプトは何で作ればいいの?
プログラミング用のテキストエディタ、Notepad++がおすすめです。

H10+EliteHRV+Kubios

PolarH10+EliteHRV+Kubiosで心拍変動解析
 PolarH10は、運動研究分野で広く使われるチェストバンド型心拍モニターであり、多くの研究に採用されています。EliteHRVは、PolarH10と併用することでHRV測定を行うことのできるスマートフォンソフトウェアであり、無料で利用できます。HF・LFパワーやSDNN、RMSSDなど、基本的なHRV指標をPC無しで確認できます。Kubiosは、HRV解析に広く用いられるソフトウェアであり、機能を限定したStandard版を無料で利用することができます(有料版は、エラー補正機能など、より先進的な追加機能を使用することができます)。Kubiosのマニュアルは、HRV解析を理解する上で非常に参考になります。
 これらのハードウェア・ソフトウェアの組み合わせは、心拍・心拍変動の計測と解析を行う上で、コストパフォマンスの高い優れた方法と言えます。下記動画に大まかな手順を示したので、研究や実験演習における、心拍・心拍変動解析に導入されてはいかがでしょうか。

Schaffarczyk, M., Rogers, B., Reer, R., & Gronwald, T. (2022). Validity of the polar H10 sensor for heart rate variability analysis during resting state and incremental exercise in recreational men and women. Sensors, 22(17), 6536. 

Perrotta, A. S., Jeklin, A. T., Hives, B. A., Meanwell, L. E., & Warburton, D. E. (2017). Validity of the elite HRV smartphone application for examining heart rate variability in a field-based setting. The Journal of Strength & Conditioning Research, 31(8), 2296-2302. 

Tarvainen, M. P., Niskanen, J. P., Lipponen, J. A., Ranta-Aho, P. O., & Karjalainen, P. A. (2014). Kubios HRV–heart rate variability analysis software. Computer methods and programs in biomedicine, 113(1), 210-220.

Arduinoで生理指標を測る

論文中で必要とする電子部品等は下記から入手可能です。
秋月電子
スイッチサイエンス
RS

Arduinoを用いた電子工作の参考サイト
ブレッドボードの使い方
Arduino 日本語リファレンス
アナログ回路の基礎

参考になる文献・書籍
・神崎 康宏(2012)Arduinoで計る,測る,量る : 計測したデータをLCDに表示,SDカードに記録,無線/インターネットに送る方法を解説 CQ出版 
https://ci.nii.ac.jp/ncid/BB08696362
・鈴木 哲哉(2014)ボクのArduino工作ノート 改訂版 ラトルズ 
https://ci.nii.ac.jp/ncid/BB1457169X
・増田正・大路駿介  (2020). PT・OT・アスリートのためのプログラミングとマイコン電子工作入門 (1) プログラミングとマイコンを用いた電子工作. バイオメカニズム学会誌, 44, 48-52.
https://www.jstage.jst.go.jp/article/sobim/44/1/44_48/_pdf/-char/ja
・増田正, & 大路駿介. (2020). PT・OT・アスリートのためのプログラミングとマイコン電子工作入門 (2) Arduino® マイコンと電子回路の活用. バイオメカニズム学会誌, 44(2), 119-123.
https://www.jstage.jst.go.jp/article/sobim/44/2/44_119/_pdf/-char/ja

論文中で紹介されたプログラムを掲載します。

ECG測定に用いたプログラム(Arduino)

#include <Wire.h> //I2C通信ライブラリ
#include <Adafruit_ADS1X15.h> //ADS1015ライブラリ
Adafruit_ADS1015 ads; //ADS1015クラスのインスタンス化

void setup(void)
{
  Serial.begin(115200);  //シリアル通信開始
  // ADS1015 gain 2/3  input range +/- 6.144V 
  ads.begin(); //ADS1015通信開始
}

void loop(void)
{
  int16_t results; //AD変換結果
  results = ads.readADC_Differential_0_1();  //差動入力
   
  float   multiplier = 3.0F;  // デフォルトゲイン(2/3倍)における係数
  Serial.print(results * multiplier); //得られたデジタル値をmvに換算しシリアルモニタに表示
  Serial.print(",4000,1000"); 
  Serial.println(); //シリアルモニタ改行
  delay(0);
}

EMG測定に用いたプログラム(Arduino)

#include <Wire.h>
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;

void setup(void)
{
  Serial.begin(115200);
  // ADS1015 gain 16x  input +/- 0.256V
  ads.setGain(GAIN_SIXTEEN); //ゲインを16倍に設定
  ads.begin();
}

void loop(void)
{
  int16_t results;
  results = ads.readADC_Differential_0_1();  //差動入力   

  float multiplier = 0.125F; //ゲイン16倍時の係数
  Serial.print(results * multiplier); 
  Serial.print(",100,-100"); 
  Serial.println();
  delay(0);
}

SCC測定に用いたプログラム(Arduino)

#include <Wire.h>
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;

void setup(void)
{
  Serial.begin(115200);
  // ADS1015 gain 8x  input +/- 0.512V
  ads.setGain(GAIN_EIGHT);  //ゲインを8倍に設定
  ads.begin();
}

void loop(void)
{
  int16_t results1,results2;
  results1 = ads.readADC_Differential_0_1();  //差動入力
    
  float   multiplier = 0.25F; //ゲイン8倍時の係数
  Serial.print(results1 * multiplier); 
  Serial.print(","); 
  Serial.print("194,"); //24k Ohm = 42uS
  Serial.print("-7,");  //1M Ohm = 1uS
  Serial.println();

  delay(200);
}

SCLおよびSCR測定に用いたプログラム(Arduino)

#include <Wire.h>
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;

void setup(void)
{
  Serial.begin(115200);
  // ADS1015 gain 2x  input +/- 2.048V
  ads.setGain(GAIN_TWO);        
  ads.begin();
}

void loop(void)
{
  int16_t results1,results2;
  results1 = ads.readADC_Differential_0_1();  //作動入力
  results2 = ads.readADC_Differential_2_3();
  
  float   multiplier = 1.0F;
  Serial.print(results1 * multiplier); 
  Serial.print(","); 
  Serial.print(results2 * multiplier); 
  Serial.print(",");   
  Serial.print("1111,"); //24k Ohm = 42uS
  Serial.print("-41,");  //1M Ohm = 1uS
  Serial.println();

  delay(200);
}

EMGの無線計測に用いたプログラム(Arduino)

#include "BluetoothSerial.h" //BT通信ライブラリ
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
Adafruit_ADS1015 ads;
BluetoothSerial SerialBT; //BluetoothSerial クラスのインスタンス化
long t1,t0; //時間管理用変数
int cnt=0; //加算回数
int16_t results;
float multiplier = 0.125F;
float mv,average,sum; //平均値算出用変数

void setup(void)
{
  pinMode(10, OUTPUT); //内蔵赤色LEDを出力モードに
  digitalWrite(10, LOW); //内蔵赤色LEDを点灯

  Serial.begin(115200);
  SerialBT.begin("EMG32"); //Bluetooth device name
  Wire.begin(32, 33); //32端子をSDA,33端子をSCLとしてI2C通信開始
  
  // ADS1015 gain 16x  input +/- 0.256V
  ads.setGain(GAIN_SIXTEEN);
  ads.begin();
}

void loop(void)
{
  results = ads.readADC_Differential_0_1();  //作動入力   
  mv=abs(results * multiplier); //筋電位の絶対値を得る
  sum+=mv;  
  cnt++;
  
  t0=t1;
  t1=millis()/10;   //10ms間隔で平均mV数を表示
  if(t1!=t0){    
    average=sum/cnt;
    SerialBT.print(average);
    SerialBT.print(",100,0");
    SerialBT.println();
    sum=0;
    cnt=0;
  }  
}

SCCをWi-Fi経由でサーバーに送信するプログラム(Arduino)

#include <WiFi.h> //Wifiライブラリ
#include <WiFiMulti.h> //複数のアクセスポイントを管理するためのクラス
#include <HTTPClient.h>//HTTP通信ライブラリ
#include <Wire.h>
#include <Adafruit_ADS1X15.h>

WiFiMulti wifiMulti; //WiFiMultiクラスのインスタンス化
Adafruit_ADS1015 ads;

void setup(void)
{
  pinMode(10, OUTPUT);
  digitalWrite(10, LOW);

  Serial.begin(115200);
  Wire.begin(32, 33); //I2C connection
  
  ads.setGain(GAIN_EIGHT);  // ADS1015 gain 8x
  ads.begin();

  delay(4000);  //4秒待機した後に通信開始
  wifiMulti.addAP("MySSID", "MyPassword"); //WiFiアクセスポイントの登録
}

void loop(void)
{
  int16_t results;
  float multiplier = 0.25F;
  float SC;
  results = ads.readADC_Differential_0_1();  //作動入力   
  SC=results * multiplier;

  if((wifiMulti.run() == WL_CONNECTED)) { //登録したアクセスポイントに接続
    HTTPClient http; //HTTPClientをインスタンス化
    Serial.print("[HTTP] begin...\n");
    String URL="http://hogehoge.ne.jp/hogehoge/getsc.php";
    URL+="?SC="+String(SC);
    http.begin(URL); //HTTP通信開始

    Serial.print("[HTTP] GET...\n");
    Serial.println(URL);
    int httpCode = http.GET(); //URLをGET方式でリクエスト

    if(httpCode > 0) {
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);
      if(httpCode == HTTP_CODE_OK) { //通信に成功したら
          String payload = http.getString(); //通信結果をpayloadへ格納
          Serial.println(payload);
      }
    } else { //失敗したらエラーとコードを表示
      Serial.printf("[HTTP] GET... failed, error: %s\n", 
                    http.errorToString(httpCode).c_str());
    }
    http.end(); //HTTP通信終了
  }
  delay(1000); //1秒ごとに繰り返す
}

Wifi経由受信したSCCデータをサーバーに記録するプログラム(PHP)

<?
$SCval=$_GET['SC'];	//Arduinoから送られたデータを受け取る
$timestr=strftime("%Y%m%d_%H%M%S"); 	//タイムスタンプ作成

if($SCval!=""){
	$fp=fopen("SCdata.csv","a");	//追加形式でファイル開く
	fprintf($fp,"%s,%s\n",$timestr,$SCval);	//タイムスタンプとデータを保存
	fclose($fp);		//ファイル閉じる
	echo"saved SC value!";	//Arduino側へ文字列送信
}
?>


22BF学会講習会

導入
 近年、Arduino等の安価なマイクロコンピュータを用いた電子工作が広く普及しています。これらを利用し、バイオフィードバック装置を自作し、利用する方法を紹介します。
 マイクロコンピュータの多くはAD変換機能を持っているため、様々なセンサーを接続することで測定装置として利用可能です。センサーを読み取るだけでなく、LEDやスピーカー、液晶ディスプレイなどに測定結果を出力することも可能です。シングルタスクOSを搭載しているため、測定値のリアルタイム処理できる点や、比較的コンパクトかつ低価格で装置を構成可能な点も、バイオフィードバックへの応用に適しています。
 本講習会では、末梢皮膚温変化を題材に、ハードウェア・ソフトウェアの両面から、バイオフィードバック装置の動作を学びます。 

装置の構成
 マイクロコンピュータはArduinoUNOを、皮膚温センサーはLM35DZを用います。フィードバック部分は、視覚フィードバックにカラーLEDモジュールを、聴覚フィードバックにスピーカーを用います。

測定の方法
 センサーはメンディングテープを用い、非利き手人差し指の腹側に装着する。テープをきつく巻き過ぎて指が圧迫されないように注意する。計測中は手のひらを上に向ける。下側に向けると机の温度を測ることになるので注意。室内温度は23~25℃程度に調節し、エアコンの風が直接指先にあたらないよう、風量・風向を調節する。


学習の手順
 ここでは下記の順序でバイオフィードバック機器の動作を学んでいきます。

プログラム名:ADC・・・AD変換の基礎
プログラム名:temp01・・・基本的な皮膚温測定
プログラム名:temp02・・・より細かく皮膚温を測定する方法
プログラム名:Tone・・・聴覚フィードバックに用いるスピーカーの使い方
プログラム名:ColorLED・・・視覚フィードバックに用いるスピーカーの使い方
プログラム名:TempABF・・・聴覚を用いた皮膚温バイオフィードバックの方法
プログラム名:TempVBF・・・視覚を用いた皮膚温バイオフィードバックの方法
プログラム名:TempAVBF・・・視聴覚を用いた皮膚温バイオフィードバックの方法

 使用するプログラム一式は下記のアドレスからダウンロードできます。Zip形式で圧縮されているため、必ず展開してから使用してください(圧縮されたままだとプログラムが動作しません)。

 ハードウェアの組み立ては、各プログラムの動画と下の画像をご覧ください。

プログラム:ADC
 AD変換は生体計測をする上で欠かすことのできない方法です。ここでは、ArduinoUNOを用い、皮膚温センサーから得られる電圧をAD変換し、数値として表示する方法を学びます。

//A0に入力された値をAD変換し表示
void setup() {
  Serial.begin(115200);        // シリアル通信の初期化
}

void loop() {
  int val = analogRead(0);
  Serial.println(val);        //analog0の値を表示
  delay(1000);
}

プログラム:temp01
 AD変換された値には単位がありません。デジタル化された値をmVに換算することで、温度を表示する方法を学びます。今回用いる皮膚温センサーは、1℃あたり10mVの出力があるため、mV値を0.1倍することで温度を得ることができます。

//1秒間隔でデジタル値を取得して温度に変換し表示
double mv,temp;

void setup() {
  Serial.begin(115200);         // シリアル通信の初期化
  analogReference(INTERNAL);    //参照電圧を1.1Vに設定
}

void loop() {
  mv = (double)1100/(double)1024 * analogRead(0); //デジタル値を電圧に変換
  temp=mv*0.1;           //電圧を温度に変換
  Serial.print(mv);  
  Serial.print(",");
  Serial.print(temp);   //温度表示
  Serial.println();
  delay(1000);          //1000ms停止
}

プログラム:temp02
 皮膚温の精神的な変化は微弱であるため、自己制御を実現するためには、0.01℃程度の変化を測定する必要があります。ここでは、1秒間の平均値を算出することで、より細かく皮膚温を調べる方法を学びます。

//1秒間隔で可能な限りデジタル値を取得して平均を表示
double mv,temp;
double sum,average;
long t,t0,cnt;

void setup() {
  Serial.begin(115200);        // シリアル通信の初期化
  analogReference(INTERNAL);    //参照電圧を1.1vに設定
  cnt=sum=0;
}

void loop() {
  t0=t;
  t=millis();   //現在時刻をms単位で取得
  mv = (double)1100/(double)1024 * analogRead(0); //デジタル値を電圧に変換
  sum=sum+mv;   //mv値の足し込み
  cnt++;
  if(t0/1000 !=t/1000){       //1秒(1000ms)毎に平均算出
    average=sum/(double)cnt;  //平均を計算
    temp=average*0.1;         //電圧を温度に変換
    Serial.print(cnt);        //サンプル数表示
    Serial.print(",");
    Serial.print(average);    //平均電圧を表示
    Serial.print(",");
    Serial.print(temp);       //温度を表示
    Serial.println();
    sum=0;cnt=0;              //合計値とカウントを初期化
  }
}

プログラム:Tone
 聴覚フィードバックに用いるスピーカーの使用方法を学びます。tone命令を用いることで、出力する音の周波数と、長さを指定できます。プログラム中の12は、デジタルポートの12番から音を出す事を意味します。

//スピーカーから500Hz,1000Hzの音を表示
void setup() {
}

void loop() {
  tone(12, 500, 100);   //500Hz 100ms
  delay(1000);          //1000ms停止
  
  tone(12, 1000, 100);  //1000Hz 100ms
  delay(1000);          //1000ms停止
}

プログラム:ColorLED
 視覚フィードバックに用いるカラーLEDの使用方法を学びます。カラーLEDの制御には、Adafruit_NeoPixelライブラリを用います(ライブラリのインストール方法は動画をご覧ください)。プログラム冒頭で、デジタルポートの13番を制御用に使うこと、LEDの数が1個であることを定義しています。プログラムは、setup関数で初期化を行い、loop関数でLEDの点灯を処理しています。色のセットは、pixels.clear→pixels.setPixelColor→pixels.showの順で行います。pixels.Color(R, G, B)の形式で、色の強さは0~255で指定します。

//カラーLEDを用い、赤・緑・青色を点灯
#include <Adafruit_NeoPixel.h>
#define PIN 13        //制御用ピン
#define NUMPIXELS 1   //LEDの数
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  pixels.begin();     //LEDを初期化
}

void loop() {
  pixels.clear();
  pixels.setPixelColor(0, pixels.Color(20, 0, 0));  //赤
  pixels.show();
  delay(1000);    //1000ms停止

  pixels.clear();
  pixels.setPixelColor(0, pixels.Color(0, 20, 0));  //緑
  pixels.show();
  delay(1000);    //1000ms停止

  pixels.clear();
  pixels.setPixelColor(0, pixels.Color(0, 0, 20));  //青
  pixels.show();
  delay(1000);    //1000ms停止
}

プログラム:TempABF
 皮膚温変化を聴覚刺激として2値(上昇もしくは下降)でフィードバックします。上昇・下降は23行において求められる皮膚温変化量によって判定します。25行から27行では、温度変化に応じて上昇下降の方向を求めています。29行から34行では、変化の方向に応じてフィードバックする音を、500Hzもしくは1000Hzに振り分けています。36行から41行は、現在温度や変化量をシリアルモニタに表示しています。

//皮膚温を聴覚でフィードバック
double mv,temp0,temp1,tempd;
double sum,average;
long t,t0,cnt;

void setup() {
  Serial.begin(115200);         // シリアル通信の初期化
  analogReference(INTERNAL);    //参照電圧を1.1vに設定
  cnt=sum=0;
}

void loop() {
  t0=t;
  t=millis(); //現在時刻をms単位で取得
  mv = (double)1100/(double)1024 * analogRead(0); //デジタル値を電圧に変換
  sum=sum+mv;
  cnt++;  
  if(t0/1000 !=t/1000){   //1秒(100ms)毎に平均算出
    average=sum/(double)cnt;  //平均を計算

    temp0=temp1;          //前回の温度を保存
    temp1=average*0.1;    //電圧を温度に変換
    tempd=temp1-temp0;    //温度変化量を算出

    int mag,dir;  //変化の程度(mag)と方向(dir)
    if(tempd>0){mag=abs(tempd*100); dir=1;}   //温度上昇時
    if(tempd<=0){mag=abs(tempd*100); dir=-1;} //温度下降時
       
    if(dir==1){
      if(mag>0){tone(12, 500, 10);}                     //温度上昇時は500Hz
    }
    if(dir==-1){
      if(mag>0){tone(12, 1000, 10);}                    //温度下降時は1000Hz
    }

    Serial.print(temp1);  Serial.print(",");  //現在温度
    Serial.print(tempd);  Serial.print(",");  //温度変化量 
    Serial.print(mag);    Serial.print(",");  //変化の強さ
    Serial.println();
    sum=0;cnt=0;
    delay(10);  
  }
}

プログラム:TempVBF
 皮膚温変化を視覚刺激として色と強さでフィードバックします。具体的には、上昇時は赤、下降時は青でLEDが点灯し、皮膚温の変化量が大きいほど明るく光ります。変化量の算出、上昇・下降の判定方法はTempABFと同様です。視覚フィードバックを処理する34行から41行では、上昇の場合に

1
pixels.Color(mag, 0, 0)
で赤色に、下降の場合には
1
pixels.Color( 0, 0,mag)
で青色に、LEDを点灯させています。magには、皮膚温変化量tempdを100倍した値が入っていますので、変化量が大きいほど強く光ります。それ以外の処理は、TempABFと同様です。

//皮膚温を視覚でフィードバック
#include <Adafruit_NeoPixel.h>
#define PIN        13 
#define NUMPIXELS 1
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
double mv,temp0,temp1,tempd;
double sum,average;
long t,t0,cnt;

void setup() {
  Serial.begin(115200);         // シリアル通信の初期化
  analogReference(INTERNAL);    //参照電圧を1.1vに設定
  cnt=sum=0;
  pixels.begin();               //LEDを初期化
}

void loop() {
  t0=t;
  t=millis(); //現在時刻をms単位で取得
  mv = (double)1100/(double)1024 * analogRead(0); //デジタル値を電圧に変換
  sum=sum+mv;
  cnt++;  
  if(t0/1000 !=t/1000){   //1秒(100ms)毎に平均算出
    average=sum/(double)cnt;  //平均を計算

    temp0=temp1;          //前回の温度を保存
    temp1=average*0.1;    //電圧を温度に変換
    tempd=temp1-temp0;    //温度変化量を算出

    int mag,dir;  //変化の程度(mag)と方向(dir)
    if(tempd>0){mag=abs(tempd*100); dir=1;}   //温度上昇時
    if(tempd<=0){mag=abs(tempd*100); dir=-1;} //温度下降時
       
    pixels.clear();
    if(dir==1){
      pixels.setPixelColor(0, pixels.Color(mag, 0, 0)); //温度上昇を赤で表示
    }
    if(dir==-1){
      pixels.setPixelColor(0, pixels.Color( 0, 0,mag)); //温度下降を青で表示
    }
    pixels.show();

    Serial.print(temp1);  Serial.print(",");  //現在温度
    Serial.print(tempd);  Serial.print(",");  //温度変化量 
    Serial.print(mag);    Serial.print(",");  //変化の強さ
    Serial.println();
    sum=0;cnt=0;
    delay(10);  
  }
}

プログラム:TempVABF
 TempVABFは、視覚・聴覚、双方のフィードバックを行うものです。内容は、TempVBFに聴覚フィードバック処理(37・41行部分)を追加しただけです。

//皮膚温を視聴覚でフィードバック
#include <Adafruit_NeoPixel.h>
#define PIN        13 
#define NUMPIXELS 1
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
double mv,temp0,temp1,tempd;
double sum,average;
long t,t0,cnt;

void setup() {
  Serial.begin(115200);         // シリアル通信の初期化
  analogReference(INTERNAL);    //参照電圧を1.1vに設定
  cnt=sum=0;
  pixels.begin();               //LEDを初期化
}

void loop() {
  t0=t;
  t=millis(); //現在時刻をms単位で取得
  mv = (double)1100/(double)1024 * analogRead(0); //デジタル値を電圧に変換
  sum=sum+mv;
  cnt++;  
  if(t0/1000 !=t/1000){   //1秒(100ms)毎に平均算出
    average=sum/(double)cnt;  //平均を計算

    temp0=temp1;          //前回の温度を保存
    temp1=average*0.1;    //電圧を温度に変換
    tempd=temp1-temp0;    //温度変化量を算出

    int mag,dir;  //変化の程度(mag)と方向(dir)
    if(tempd>0){mag=abs(tempd*100); dir=1;}   //温度上昇時
    if(tempd<=0){mag=abs(tempd*100); dir=-1;} //温度下降時
       
    pixels.clear();
    if(dir==1){
      pixels.setPixelColor(0, pixels.Color(mag, 0, 0)); //温度上昇を赤で表示
      if(mag>0){tone(12, 500, 10);}                     //温度上昇時は500Hz
    }
    if(dir==-1){
      pixels.setPixelColor(0, pixels.Color( 0, 0,mag)); //温度下降を青で表示
      if(mag>0){tone(12, 1000, 10);}                    //温度下降時は1000Hz
    }
    pixels.show();

    Serial.print(temp1);  Serial.print(",");  //現在温度
    Serial.print(tempd);  Serial.print(",");  //温度変化量 
    Serial.print(mag);    Serial.print(",");  //変化の強さ
    Serial.println();
    sum=0;cnt=0;
    delay(10);  
  }
}

補足

・温度センサーに関して
現在温度センサーLM35DZは入手が難しくなっており、TMP36GT9Zを代用することができます。その場合は、温度算出部分を下記のように変更してください。

temp1=average*0.1-50;    //電圧を温度に変換

・使用した電子部品の入手先
ArduinoUNO
TMP36GT9Z
カラーLEDモジュール
スピーカー
ピンヘッダー
収縮チューブ
細径3心並列線