KY-039から心拍数まで
コンポーネントと消耗品
> |
| × | 1 | |||
| × | 1 | ||||
| × | 1 |
このプロジェクトについて
Arduino用の37個のセンサーのセット 、ハートビートセンサーがあります。名前は約束しすぎです。人々はそれがI2Cまたはそれに類似したものを介してデジタル番号を提供すると考える傾向があります。これは心拍数です。センサーが提供するのは、0〜1023の「アナログ」値であり、光センサーが受け取る赤外線の量、または実際に光センサーを覆っている何かの量を示します。 。値が高いほど、赤外線は少なくなります。
つまり、IRLEDとセンサーのライトトランジスタの間に指を置きます。心拍は指の血管を拡張し、IRをフィルタリングします。これにより、脈動信号が生成されます。
このプロジェクトでは、この信号が66 BPM(1分あたりの心拍数)のような心拍数に変換される方法について説明します。
簡単な手順
KY-039センサーから値を読み取ってプロットすると、次のようになります。
<図>値は整数値です。あまり正確ではありません。代わりに、それらの束の平均を計算し、平均をプロットします。あなたはこれを手に入れます:
<図>ここでは、すでに心臓の鼓動を見ることができます。脈拍の各有意な上昇の間の時間差を取得します。そこから、BPMで心拍数を計算できます。
(上の画像の小さなジグザグパターンは、50 Hzの人工光によるもので、もう1つ対処する必要があります。)
手順の説明
KY-039センサーから読み取ったものを出力するための簡単なコードを次に示します。
//パルスモニターテストScriptintsensorPin =0; void setup(){Serial.begin(9600);} void loop(){while(1){Serial.print(analogRead(sensorPin)); Serial.print( '\ n'); }}
あなたが得るかもしれないものはこのようなものです:
<図>
これは、Arduinoからのシリアル出力を9600ボーで読み取るシリアルモニターウィンドウからのキャプションであるため、プロセス全体が Serial.print()
によってタイミングが取られます。 関数。値の読み取りとプロットの速度を設定します。とにかく、曲線は360から383の間で変化し、整数値しかないため、非常にギザギザになっています。
スムージング
よりスムーズな出力を得るには、センサーから平均20回の最後の読み取り値を取得します。これが私のやり方です。必要な読み取り値の数を示す定数を定義します:
#define samp_siz 20
次に、その数の読み取り値を保持する配列があります:
int read [samp_siz];
新しい読み取り値ごとに、合計から最も古い読み取り値を減算し、合計に最新の読み取り値を加算します。配列内で、最も古い読み取り値を最新の読み取り値に置き換えます。
reader =analogRead(sensorPin); //センサーの合計を読み取ります-=reads [ptr]; //合計から最も古い読み取り値を減算します+ =リーダー; //最新の読み取り値を合計に追加しますreads [ptr] =reader; //最新の読み取り値を配列に保存しますlast =float(sum)/ samp_siz; //今すぐ平均を計算しますptr ++; //配列のインデックスを更新します。ptr%=samp_siz; //必要に応じて0から再開します
アレイサイズが20で、シリアルモニターのボーレートが9600の場合、次のようなプロットが表示される可能性があります。
<図>ここでは、実際の心拍数が急な上昇曲線として表示されます。しかし、小さなジグザグパターンも見られます。小さいジグザグは私のキッチンライトから来ており、3つのLED電球が部屋を照らしています。私の家の主電源は240V、50 HzACです。したがって、1秒間に50回、明らかにIR帯域でも光強度が上昇します。その50Hzのノイズを滑らかにしたいと思います。 20ミリ秒の間にセンサーから値を読み取り、すべての値の平均を取ると、機能するはずです。見てみましょう...
n =0;開始=ミリ秒();リーダー=0。; do {リーダー+ =analogRead(sensorPin); //値を読み取って追加します... n ++;今=ミリ秒(); } while(now
このスニペットを使用して、センサーの読み取り値を20ミリ秒のチャンクで取得します。これにより、人工光によって引き起こされる50Hzのちらつきが均等になります。 60 Hzの国に住んでいる場合は、代わりに16.67ミリ秒のチャンクを使用してください。または16667µs。
すでに20ミリ秒のセクションで曲線を滑らかにしているので、以前に使用した配列は実際には必要ありませんが、そこにあり、簡単にサイズ変更できるので、そのままにしておきます。また、5の配列サイズを使用すると、最後の厄介なノイズが均等になるようです。これが私が今持っているものです:
<図>
私がする必要がある最後のことは、繰り返しパターンの任意の部分を認識することです。上り坂の方が規則的なので、行きます。すべてのグラフでy軸の値が大きく異なることに注意してください。絶対値だけに頼ることはできません。私はカーブの上昇と下降にのみ頼ることができます。数学者は導関数について話します。 n を見つけたら、満足しています
連続する上昇値。ここで、 n
便利な調整可能な値になる可能性があります。私は5から始めます。これには rise_threshold
があります。 コードで定義された定数。 5つの連続する上昇値を見つけたとき、私はカーブの一番下に向かっていることがわかります。時間がかかります。下降曲線を待ち、次に次の5つの上昇値を待ち、時間を記録します。次に、対応するBPMを印刷します。
テストを行いました および カウント 方法 多く 連続 上昇 値 あります は in 曲線 および 見つかりました アウト あります だった 間 10 および 15。 だから if 私 カウント から 5、 私 予定 ほとんど 確かに 知っている 私は 見つかりました 開始 of ハートビート。
ハートビートごとに印刷するので、あまり印刷されません。センサーを読み取るためのより多くの時間があります。プロッタがオンになっていないため、頻繁に発生するノイズが発生する可能性がありますが、これは表示されません。それがどのように機能するか見てみましょう。
最終的なコード
#define samp_siz 4#define rise_threshold 5 //パルスモニターテストScriptintsensorPin =0; void setup(){Serial.begin(9600);} void loop(){float read [samp_siz]、sum; long int now、ptr;最後にフロート、リーダー、スタート; float first、second、third、before、print_value;ブール上昇; int rise_count; int n; long int last_beat; for(int i =0; i before){rise_count ++; if(!rising &&rise_count> rise_threshold){//わかりました、上昇曲線を検出しました。ハートビート。//最後のビートからの時間を記録し、前の2回を追跡します//(最初の、2番目、3番目)加重平均を取得します。 //上昇フラグは、同じ上昇を//複数回検出することを防ぎます。上昇=真; first =millis()-last_beat; last_beat =millis(); //心拍数の加重平均を計算します//最後の3つの拍数に従ってprint_value =60000。/(0.4*最初の+ 0.3 * 2番目の+0.3 * 3番目); Serial.print(print_value); Serial.print( '\ n'); 3番目=2番目; 2番目=最初; }} else {//わかりました、曲線は下降しています上昇=false; rise_count =0; } before =last; ptr ++; ptr%=samp_siz; }}
それはかなりうまくいきます。これがビデオです。
小さなRXLEDが私の心と同期してArduinoで点滅することに注意してください。ハートビートがあるとき、レートが計算されてシリアルに印刷され、LEDが点滅するからです。指を少し動かすと、読み取りエラーが発生します。
さらなる開発
現在、印刷されたレートは最後の3ビートに基づいて計算されています。ただし、たとえば15秒の期間に基づいて計算する方が適切な場合があります。 15の連続したレート値を保存し、平均を計算してから、平均から最も遠い5つの値を除外して、新しい平均を計算することができます。これにより、心拍数の信頼性が高く安定した測定値が得られます。
私は妻と私でのみセンサーをテストしました。以前の測定値に基づいて作成した信号を強化するための各ステップ。他の誰かが別の種類の心拍を持っていて、別の形の曲線を引き起こしている可能性があります。これには、拍を見つけるための別のアプローチが必要です。多分それは認識しやすい下降曲線です。または一番上。そして、パルスが180〜200 BPMの場合はどうなりますか?上昇曲線を見つけるのは難しいかもしれません。
コード
- 最終バージョン
最終バージョン C / C ++
プログラムはハートビートを読み取り、シリアルウィンドウにレートを出力します。#define samp_siz 4#define rise_threshold 4 //パルスモニターテストスクリプトintsensorPin =0; void setup(){Serial.begin(9600);} void loop (){float read [samp_siz]、sum; long int now、ptr;最後にフロート、リーダー、スタート; float first、second、third、before、print_value;ブール上昇; int rise_count; int n; long int last_beat; for(int i =0; ibefore){rise_count ++; if(!rising &&rise_count> rise_threshold){//わかりました、上昇曲線を検出しました。ハートビート//最後のビートからの時間を記録し、加重平均を取得するための2つの前の//回(1回目、2回目、3回目)。 //上昇フラグは、同じ上昇を複数回検出することを防ぎます。上昇=真; first =millis()-last_beat; last_beat =millis(); //心拍数の加重平均を計算します//最後の3つの拍数に従ってprint_value =60000。/(0.4*最初の+ 0.3 * 2番目の+0.3 * 3番目); Serial.print(print_value); Serial.print( '\ n'); 3番目=2番目; 2番目=最初; }} else {//わかりました、曲線は下降しています上昇=false; rise_count =0; } before =last; ptr ++; ptr%=samp_siz; }}
回路図
製造プロセス