質問: millis() ; Serial.print(time/1000) ; Serial.print(",") ; Serial.println(now*0.005); //Serial.println(now); //delay(10); if(now>peak) {//ピーク値更新なら peak=now;//保存して tNow=millis();//時間を取得 j=1;//取得した } if(now
回答: やりたいことは、直近の山の頂上から20%下がったときの時間間隔を測定したい、ということだと読み取りましたがよろしいですか? まず。 > > コンパイル時のエラー等はありません。 > > > とのことですが、 ### 重大なバグがあります。 ArduinoのベースとなるC++言語では「コンパイルエラーにはならない(特別な使い方をするためにエラーにしない)けれど普通はやってはいけないこと」がゴマンとあって、その一つに「確保した配列の範囲外にアクセスすること」というのがあります。 ``` unsigned long t200] ; //<<<略>>> t[i] = millis(); //i=0の時は計算できないので分岐 if (i != 0) { to = t[i] - t[i - 1]; //入れるに格納された秒数からRR間隔を計算 //ケーブルを通してPCに出力 Serial.println("RR"); Serial.println(to); } i++; //次の配列へ ``` t[200]として宣言されていますので、配列の添字としては(原則として)0~199の範囲外で使ってはいけません。しかし、t[]の添字として使われているiは、何の制限もなくどんどん増えていきます。ダメです。 配列の範囲外にアクセス、特に書き込みを行ったときに何が起こるか、全く予想出来ない事態になります。他の変数の値を滅茶苦茶にしたり、あるいはプログラムの動作を不可能にしたり、いろいろ悪さをします。 この部分は「前回の時刻-今回の時刻」の計算をしているだけですから、過去の値を配列で全部保存している必要はないはずです。 ``` unsigned long tNow, tPrev; //<<<略>>> tNow = millis(); //i=0の時は計算できないので分岐 if (i != 0) { to = tNow - tPrev; //前回の時刻から引けばRR間隔が求まる tPrev = tNow; //前回の時刻として保存 //ケーブルを通してPCに出力 Serial.println("RR"); Serial.println(to); } i++; ``` で十分では。 つぎ。 ``` a = analogRead(A5); //アナログ入力の代入 //閾値を決める if (a - x > 0) { x = a; //波形の山が下り始めるところを見つける if (x - threshold > 0) { threshold = a; //R波のみ判定 } } ``` この部分から読み取れることは、 `if (a - x > 0) {` aの方が大きければxを書き換えている、つまりxは**測定開始以来最大の**シグナル値を保持している。 `if (x - threshold > 0) {` xの方が大きければthresholdを書き換えている。つまり、thresholdも同じことで測定以来最大のシグナル値を保存している。 xの存在は無駄です。そしてなにより、波形の山が下がり始めるところをみつけているわけではありません。 結果として、 ![イメージ説明 最初低い山があると(1)でthresholdが確定して、その0.8倍で最初のRR判定が行われます(2)。 次に高い山があると(3)thresholdが更新され、以降低い山があってもRR判定には引っかからない、ということになります。これは意図した動作でしょうか。Wikipediaの心電図の項の画像のようなのが典型パターンとすると、それでも破綻はしないのかも知れませんが、しかしRの高さが20%以上変動があるといろいろと支障が出そうな気がします。 この辺の判別方法は要検討ではないでしょうか。 なお、データをどう処理すればいいのかはプログラミングの問題ではありません。プログラムは「あなたがやらせたいことをコンピュータにわかるように書き下しただけの文書であって、プログラムがなにかを解決してくれるわけではなく、コンピュータに何をやらせればいいかはプログラム以前に決まっているはずの話です。