前提・実現したいこと
M5Stackを使って、一拍の時間を測ってそれを60秒で割って心拍数をだそうとしています。
前回、同じ質問をしましたが、さすがに変なところがあったのでほんの僅かですが修正したもので再投稿させていただきました。
CircularBuffer.hというライブラリを使ってます。
しばらく待ってみたら値が60~80を行ったり来たりしました。
もしかしたら本当はうまく動いていて想定していたものが現れるまで時間がかかるだけなのかもしれません。
参考にしたサイトのように激しく値が動かないだけなのかも
発生している問題・エラーメッセージ
プログラミング自体にはエラーは出ていないが、動作結果が想定していたものが表示されない。 上手くif文の条件に入らないのが原因なのかグラフに変化がない(上図みたいな) 本来?理想とするのは参考にしたサイトのような下図の青い線のように表示したい。
該当のソースコード
arduino IDE
ソースコード
#include <M5Stack.h> #include <Wire.h> #include "MAX30105.h" #include "CircularBuffer.h" MAX30105 Sensor;//MAX30105を定義 CircularBuffer<int, 100> buffer_ir; //リングバッファを定義容量は100 CircularBuffer<int, 100> buffer_red; CircularBuffer<int, 3> avgHR; //それぞれ定義 const int32_t TH_AMOUNT = 300; //パルスの起点となる変化量これを超えるとパルスの起点となる int32_t a = 0; //カウント用変数 int32_t c = 0; float sum_ir = 0.0; float sum_red = 0.0; float sum_hr = 0.0; float sum_spo2 = 0.0; const int32_t MIN_INIT = 9999999; //最小値の初期値 const int32_t MAX_INIT = 0; //最大値の初期値 double ir_v_dc; double red_v_dc; double hr; //double spo2; long l_time = millis(); int32_t before_ir_v = 0; int32_t b_diff = 0; long pulse_interval = -1; //表示する心拍数とSpO2の範囲(用途により適宜変更) const uint32_t DISP_MIN_HR = 30; const uint32_t DISP_MAX_HR = 180; const uint32_t DISP_MIN_SPO2 = 70; const uint32_t DISP_MAX_SPO2 = 100; //1パルス中の生データの最大・最小値の保持 int32_t min_ir_v = MIN_INIT; int32_t min_red_v = MIN_INIT; int32_t max_ir_v = MAX_INIT; int32_t max_red_v = MAX_INIT; void setup() { M5.begin(); M5.Power.begin(); Serial.begin(115200); M5.Lcd.clear(BLACK); while (!Sensor.begin(Wire, I2C_SPEED_FAST)) { //MAX30105を初期化 Serial.print("."); } Serial.println("OK!"); //サンプリングレート等を設定 byte ledBrightness = 0x1f; byte sampleAverage = 4; byte ledMode = 2; int sampleRate = 400; int pulseWith = 411; int adcRange = 4096; Sensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWith, adcRange); //初期値として読んでおく before_ir_v = Sensor.getIR(); //初期値として値をいれておく for (a = 0; a < 100; a++) { buffer_ir.unshift(Sensor.getIR()); sum_ir += buffer_ir.first(); } for (c = 0; c < 3; c++) { avgHR.unshift(0); sum_hr += avgHR.first(); } //パルス最終取得時間の初期化 l_time = millis(); } void loop() { uint32_t ir_v = Sensor.getIR(); uint32_t red_v = Sensor.getRed(); //移動平均を算出するためのプログラム ir_v_dc = sum_ir / 100.0; //平均を算出 sum_ir -= buffer_ir.last(); //総和から一番古いデータを引く buffer_ir.unshift(ir_v);//リングバッファにir_vの値を入れる sum_ir += buffer_ir.first(); //IRとREDのACを求める為に最大値・最初値の更新 if (ir_v < min_ir_v) min_ir_v = ir_v; if (ir_v > max_ir_v) max_ir_v = ir_v; //パルス検出にはir_vを利用。前回との差分を求める int32_t diff = before_ir_v - ir_v; //TH_AMOUNT以上の差がある場合、パルス起点とする if (diff > TH_AMOUNT && b_diff < TH_AMOUNT){ //1パルスの時間を計算 pulse_interval = millis() - l_time; l_time = millis(); //平均を算出 hr = sum_hr / 3.0; sum_hr -= avgHR.last(); //総和から一番古いデータを引く //心拍数の計算、結果をリングバッファに入れる avgHR.unshift((60000 * 1000 / pulse_interval) / 1000); sum_hr += avgHR.first(); //最大値・最小値の初期化 min_ir_v = MIN_INIT; max_ir_v = MAX_INIT; Serial.print(hr); } Serial.print(hr); //Serial.print(","); //Serial.print(ir_v); //Serial.print(","); //Serial.println(ir_v_dc); //パルス検出用値の保持 before_ir_v = ir_v; b_diff = diff; }
試したこと
このプログラミングはTH_AMOUNTの値を超えたらそこを起点として一拍の時間を測るようなことをしています。
その値を小さくしたり大きくしたりしてもうまく表示させることが出来ませんでした。
補足情報(FW/ツールのバージョンなど)
途中生データの移動平均を出しているところがありますが、それは心拍数と関係ありません。
こちらを参考にしました。
https://androiphone.uvs.jp/?p=3027
しばらく待ってみたら値が60~80を行ったり来たりしました。
もしかしたら本当はうまく動いていて想定していたものが現れるまで時間がかかるだけなのかもしれません。