Kết luận chương 4

Một phần của tài liệu Nghiên cứu thiết kế hệ thống theo dõi nhịp tim bằng arduino uno và processing (Trang 74 - 100)

Chương 4 trình bày việc thực thi thiết kế Module đo và giám sát nhịp tim

- Nêu ra được nguyên lí của phần cứng và có hình ảnh minh họa về phần cứng kết nối với máy tính.

- Có đầy đủ những hình ảnh mô phỏng chụp lại được từ giao diện phần mềm Processing, từ những hình ảnh thu được đó chúng ta có thể đánh giá được tình trạng sức khỏe nói chung và các thông số của nhịp tim nói riêng.

- Đánh giá các yếu tố ảnh hưởng đến sai số của phép đo và các hình ảnh so sánh với các sản phẩm đo nhịp tim của các hãng khác nhau.

KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN

Về cơ bản báo cáo và sản phẩm đã đạt được những yêu cầu đặt ra của đề tài, đó là: Tìm hiểu cấu trúc, hoạt động của tim và tầm quan trọng của nhịp tim đối với sức khỏe con người. Giới thiệu các phương pháp đo nhịp tim phổ biến hiện nay và đề xuất phương án thiết kế. Tìm hiểu về các thông số của nhịp tim, cơ sở thu nhận tín hiệu điện tim. Phân tích cơ sở thiết kế và thực thi Module đo và giám sát các thông số về nhịp tim. Thiết kế một module xác định nhịp tim bằng đầu đo cảm biến gắn trên đầu ngón tay, đồng thời hiện thị các thông số đo được về nhịp tim như Beats Per Minute (BPM), Interbeat Intervals (IBI), Heart Rate Frequency (Hz), Power Spectral Density (PSD), LF vs HF (Low Frequency vs High Frequency), Phổ tần số, Phổ BPM, Phổ IBI, Beats, Hiệu năng HF, LF và dạng sóng HR lên một giao diện trực quan được xây dựng trên phần mềm Processing của máy tính.

Đề tài có thể được phát triển thêm khi có thể thu gọn lại kích thước sản phẩm (sử dụng vi điều khiển nhỏ hơn), các thông số về nhịp tim hiện thị trên màn hình LCD và đeo được hoặc có thể giám sát trên màn hình máy tính thông qua các Module không dây như Zigbee, giám sát từ xa qua ứng dụng trên điện thoại hay trên Websever.

TÀI LIỆU THAM KHẢO

[1] Kil-sang Yoo and Won-hyung Lee Chung-Ang University, “Metal stress assessment based on pulse photoplethysmogram,” International Symposium on Consumer Electronics IEEE 15th, 2011.

[2] “Heart rate variability Standards of measurement,” physiological interpretation, and clinical use Task Force of The European Society of Cardiology and The North American Society of Pacing and Electrophysiology (Membership of the Task Force listed in the Appendix), 1996.

[3] Yu-Hao Lee, Vincent Shieh Chih-Lung Lin and Yung-Jong Shiah, National Cheng Kung University - National Kaohsiung Normal University, “A stress evulation and personal relaxation system based on mesurment of photoplethysmography,” Second International Conference on Robot, Vision and Signal Processing, 2013.

[4] David Pereg, Rachel Gow, Morris Mosseri, Michael Lishner, Michael Rieder, Stan Van Uum, Gideon Koren “Hair cortisol and the risk for acute myocardial infarction in adult men,” Stress The International Journal on the Biology of Stress, 2010.

[5] John T. Ramshur, University of Memphis, Department of Biomedical Engineering, Memphis, TN, HRVAS: Heart Rate Variability Analysis Software, 2010.

[6] Xu xu, “Analysis on Mental Stress/Workload Using Heart Rate Variability and Galvanic Skin Response during Design Process,” A Thesis in the Concordia Institute for Information Systems Engineering, Concordia University Montreal, Quebec, Canada, April 2014.

[7] https://www.arduino.cc/ [8] http://arduino.vn/

[9] https://processing.org/ [10] http://pulsesensor.com/

PHỤ LỤC

I. Phần mềm phụ trợ

Vì Arduino IDE được viết trên Java nên cần phải cài đặt JRE trước Arduino IDE. Link: http://www.oracle.com/technetwork/java/javase/downloads/jre7-downloads- 1880261.html

2 bản JRE phổ biến nhất là bản dành cho Windows 32bit (x86) và Windows 64bit (x64) được đánh dấu trong hình. Chọn "Accept License Agreement".

Download JRE

Tiếp theo truy cập địa chỉ http://arduino.cc/en/Main/Software/ . Đây là nơi lưu trữ cũng như cập nhật các bản IDE của Arduino, để tải phiên bản phù hợp và mới nhất về máy tính.

Processing là một ngôn ngữ lập trình mã mở, thiết kế với mục đích lập trình đồ họa trên nhiều môi trường khác nhau: Linux, Window, Mac, Android, và cả Web. Ngôn ngữ được Casey Reas và Benjamin Fry của phòng thí nghiệm đa phương tiện đại học MIT sáng tạo, nên nó cũng thích hợp cho học tập, nghiên cứu những khái

niệm cơ sở của đồ họa máy tính. Dự án processing bắt đầu năm 2001, xây dựng trên ngôn ngữ Java, nhưng sử dụng cú pháp đơn giản hơn [9].

Gói processing có kèm theo sketchbook, một IDE nhỏ phụ trợ lập trình. Mỗi sketch trong Processing là một lớp con của lớp Java PApplet. Khi lập trình Processing, tất cả các lớp định nghĩa sẽ được xếp vào lớp bên trong (inner class) khi mã Processing dịch sang Java trước khi biên dịch. Do vậy nếu không viết mã trong chế độ thuần Java, mã Processing không thể dùng các biến/ hàm tĩnh. Processing cũng cho phép người dùng tạo các lớp riêng bên trong PApplet sketch. Điều này cho phép tạo và sử dụng các kiểu dữ liệu phức tạp, không hạn chế trong các kiểu dữ liệu chuẩn như int, char (ký tự), float (số thực), và color (RGB, ARGB, hex)…

Trình soạn thảo gồm 4 phần chính: Thanh công cụ; Phần chạy chương trình (debug); Ô soạn thảo mã (code); Phần thông báo/báo lỗi.

Thanh công cụ: chứa các công cụ giúp chỉnh sửa, cài đặt cho người dùng soạn thảo một cách dễ dàng, xuất ra file cuối, trợ giúp,…

Phần chạy chương trình: Sau khi soạn thảo xong chương trình một cách hoàn chỉnh(không có lỗi), tại đây bấm vào nút Debug để chạy chương trình, trình soạn thảo sẽ biên dịch và chạy chương trình.

Ô soạn thảo: Gồm các tab, trong tab gồm các dòng được đánh dấu cho người lập trình soạn thảo mã lên đó.

Phần thông báo/báo lỗi: phần này thông báo cho người lập trình biết phần nào đang sai, để chỉnh sửa. Thông báo này sẽ có kèm theo dòng, kí thứ bao nhiêu bị sai.

Các thông tin về hướng dẫn lập trình, download phần mềm có thể vào trang https://processing.org/ để tham khảo.

II. Mã chương trình nạp cho Arduino Uno R3

/* Chuong trinh chinh */ // Variables

int pulsePin = 0; // Chan du lieu (day tim cua cam bien Pulse ket noi voi chan analog 0 cua Arduino

int blinkPin = 13; // den led tren Arduino (chan 13) nhap nhay moi khi co nhip tim

int fadePin = 5; // pin to do fancy classy fading blink at each beat int fadeRate = 0;// used to fade LED on with PWM on fadePin

// Volatile Variables, su dung cho cac vong lap thuong xuyen gian doan

volatile int BPM; // bien giu nguyen gia tri tren Analog 0, cap nhat gia tri moi 2mS

volatile int Signal; // bien giu nguyen gia tri chua xu ly den volatile int IBI = 600; // bien giu khoang thoi gian giua cac nhip dap

volatile boolean Pulse = false; // "True" khi co nhip tim nguoi. "False" khi nguoi dung khong ket noi voi cam bien

volatile boolean QS = false; // bien se co gia tri “True” khi Arduino phat hien co nhip tim

// Truyen thong noi tiep dau ra

//static boolean serialVisual = false; // mac dinh lay gia tri “False” khi co gia tri tren man hinh Serial cua Arduino thi chuyen sang “True”

void setup(){

pinMode(blinkPin,OUTPUT); // led nhap nhay theo nhip tim pinMode(fadePin,OUTPUT); // led mo di theo moi nhip tim Serial.begin(115200); // toc do Baud 115200

interruptSetup();// Cai dat doc xung moi 2mS // analogReference(EXTERNAL); } // main void loop(){ serialOutput() ;

if (QS == true){ // Neu co nhip tim, BPM va IBI duoc xac dinh

fadeRate = 255; // Lay gia tri 255 de lam mo LED khi co xung serialOutputWhenBeatHappens(); // khi co nhip tim dua du

lieu toi dau ra noi tiep

QS = false; // thiet lap lai gia tri cho QS } ledFadeToBeat(); delay(25); } void ledFadeToBeat(){

fadeRate -= 15; // set LED fade value fadeRate = constrain(fadeRate,0,255); // keep LED fade value from going into negative numbers!

analogWrite(fadePin,fadeRate); // fade LED }

void serialOutput(){ // Output Serial.

sendDataToSerial('S', Signal); // goes to sendDataToSerial function

}

// Decides How To OutPut BPM and IBI Data void serialOutputWhenBeatHappens(){

sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix

sendDataToSerial('Q',IBI); // send time between beats with a 'Q' prefix

}

// Sends Data to Pulse Sensor Processing App or Third-party Serial Readers.

void sendDataToSerial(char symbol, int data ){ Serial.print(symbol);

Serial.println(data); }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* Chuong trinh ngat*/

volatile int rate[10]; // array to hold last ten IBI values

volatile unsigned long sampleCounter = 0; // used to determine pulse timing

volatile unsigned long lastBeatTime = 0; // used to find IBI volatile int P =512; // used to find peak in pulse wave, seeded volatile int T = 512; // used to find trough in pulse wave, seeded volatile int thresh = 525; // used to find instant moment of heart beat, seeded

volatile int amp = 100; // used to hold amplitude of pulse waveform, seeded

volatile boolean firstBeat = true; // used to seed rate array so we startup with reasonable BPM

volatile boolean secondBeat = false; // used to seed rate array so we startup with reasonable BPM

void interruptSetup(){

// Initializes Timer2 to throw an interrupt every 2mS.

TCCR2A = 0x02; // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE

TCCR2B = 0x06; // DON'T FORCE COMPARE, 256 PRESCALER

OCR2A = 0X7C; // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE

TIMSK2 = 0x02; // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A

sei(); // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED }

// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE.

// Timer 2 makes sure that we take a reading every 2 miliseconds ISR(TIMER2_COMPA_vect){ // triggered when Timer2 counts to 124

cli(); // disable interrupts while we do this

Signal = analogRead(pulsePin); // read the Pulse Sensor

sampleCounter += 2; // keep track of the time in mS with this variable

int N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise

// find the peak and trough of the pulse wave

if(Signal < thresh && N > (IBI/5)*3){ // avoid dichrotic noise by waiting 3/5 of last IBI

T = Signal; // keep track of lowest point in pulse wave

} }

if(Signal > thresh && Signal > P){ // thresh condition helps avoid noise

P = Signal; // P is the peak

} // keep track of highest point in pulse wave

// NOW IT'S TIME TO LOOK FOR THE HEART BEAT

// signal surges up in value every time there is a pulse if (N > 250){ // avoid high frequency noise

if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ){ Pulse = true; // set the Pulse

flag when we think there is a pulse

digitalWrite(blinkPin,HIGH); // turn on pin 13 LED

IBI = sampleCounter - lastBeatTime; // measure time between beats in mS

lastBeatTime = sampleCounter; // keep track of time for next pulse

if(secondBeat){ // if this is the second beat, if secondBeat == TRUE

secondBeat = false; // clear secondBeat flag for(int i=0; i<=9; i++){ // seed the running total to get a realisitic BPM at startup

rate[i] = IBI; }

}

if(firstBeat){ // if it's the first time we found a beat, if firstBeat == TRUE

firstBeat = false; // clear firstBeat flag secondBeat = true; // set the second beat flag

sei(); // enable interrupts again

return; // IBI value is unreliable so discard it }

// keep a running total of the last 10 IBI values word runningTotal = 0; // clear the runningTotal variable

for(int i=0; i<=8; i++){ // shift data in the rate array rate[i] = rate[i+1]; // and drop the oldest IBI value runningTotal += rate[i]; // add up the 9 oldest IBI values }

rate[9] = IBI; // add the latest IBI to the rate array runningTotal += rate[9]; // add the latest IBI to runningTotal runningTotal /= 10; // average the last 10 IBI values

BPM = 60000/runningTotal; // how many beats can fit into a minute? that's BPM!

QS = true; // set Quantified Self flag // QS FLAG IS NOT CLEARED INSIDE THIS ISR }

}

if (Signal < thresh && Pulse == true){ // when the values are going down, the beat is over

digitalWrite(blinkPin,LOW); // turn off pin 13 LED Pulse = false; // reset the Pulse flag so we can do it again

amp = P - T; // get amplitude of the pulse wave

thresh = amp/2 + T; // set thresh at 50% of the amplitude

P = thresh; // reset these for next time

T = thresh; }

if (N > 2500){ // if 2.5 seconds go by without a beat

thresh = 512; // set thresh default P = 512; // set P default T = 512; // set T default

lastBeatTime = sampleCounter; // bring the lastBeatTime up to date

firstBeat = true; // set these to avoid noise

secondBeat = false; // when we get the heartbeat back

}

sei(); // enable interrupts when youre done!

III. Mã chương trình trên Processing

// Processing code

import org.jtransforms.fft.FloatFFT_1D; import processing.serial.*;

//import java.awt.Toolkit; // needed for the "beep" sound

boolean debug = false; // make true to print debug info to serial //boolean playBeep = false; // play beep every heart beat.

Serial myPort;

String comPort = "COM3"; int LabelSize = 24;

// FFT spectrum variables

float[] spectrumArr; // PSD spectral data

float rrData[]= new float[20]; // this defines the max number of data elements (beats) to evaluate via FFT

String rrDataStr = "";

String[] PSDlabels; // the labels are dynamically generated by FFT process

// per beat holders int beatCount = 0;

float LF = 0; // Low Frequency ( <= .15 Hz ) float HF = 0; // High Frequency ( > .15 Hz) float LFold = 0;

float HFold = 0;

// total accumulators for averages //float LFa = 0;

//float HFa = 0;

boolean firstTime = true;

color LFcolor = color(200, 255, 8); color HFcolor = color(255, 0, 255); // just for reference

// LF = .04 - .15Hz // HF = .15 - .4Hz

int BPM = 20; // seeded so the graph starts nice int IBI = 200; // inter beat interval in millis

// main waveform graph variables

int xPos = 1; // horizontal position of the graph int xPosOld = 1; // holder

float inByte = 0;

float sensorValOld = 0;

// frequency and other main variables and holders float freq = 0;

float freqMappedVal = 0;

float runningTotal = 1; // can't initialize as 0 because of math float mean; // useful for VLF derivation... int P; // peak value of IBI waveform

int amp=0; int lastIBI;

float[] powerPointX; // array of power spectrum power points float[] powerPointY;

int pointCount = 0; // used to help fill the powerPoint arrays int[] PPG; // array of raw Pulse Sensor datapoints String direction = "none";

int maxDots = 500; // after this number of beats the oldest dots begin to disappear

boolean goingUp;

int yMod = 0; // adjust to center the graph up or down reversed: -10 (up 10) and 10 (down 10)

float magnify = 1.6; // magnification of main waveform graph

int LFHFmagnify = 1; // increase the x axis speed for LF vs HF power graph

int WaveWindowX = 260; // start xposition of main waveform window

Một phần của tài liệu Nghiên cứu thiết kế hệ thống theo dõi nhịp tim bằng arduino uno và processing (Trang 74 - 100)

Tải bản đầy đủ (PDF)

(100 trang)