scieee AI-readable full text Open interactive document viewer

Disseny i implementació d'un prototip d'electrocardiògraf amb visualització del senyal en temps real

García Aparici, Joan

Abstract

El treball present en el document descriu tot el procés involucrat en el disseny i la implementació d'un prototip d'electrocardiògraf portàtil per la mesura de tres diferències de bio-potencial en el cos. A més, es detalla la creació de dues diferents aplicacions per a la visualització del senyal. La primera està dissenyada amb l'aplicació Processing, que genera una interfície gràfica en la pantalla d'un ordinador on es mostra el senyal, amb comunicació serial per l'enviament de dades. La segona està dissenyada amb un marc de treball molt nou anomenat Flutter, que ha permès crear una aplicació amb la mateixa funcionalitat per a dispositius mòbils Android, amb comunicació Bluetooth per la transmissió de dades. S'ha fet ús de la placa Arduino Uno per tal de fer el mostreig del senyal desitjat, ja que porta un ADC incorporat, així com per l'enviament de dades a través del port serial. Per a la comunicació Bluetooth, s'ha utilitzat el mòdul HC-06 conjuntament amb l'Arduino. El prototip final resulta un circuit robust muntat en una PCB i alimentat amb bateries de 9 V, el funcionament del qual es pot trobar representat tan en les dues aplicacions com en l'oscil·loscopi.

Full text

TREBALL FI DE GRAU Grau en Enginyeria Electrònica Industrial i Automàtica DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. Memòria i Annexos Autor: Joan Garcia Aparici Director: Herminio Martínez García Convocatòria: Juny 2023 DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. i Resum. El treball present en el document descriu tot el procés involucrat en el disseny i la implementació d'un prototip d'electrocardiògraf portàtil per la mesura de tres diferències de bio-potencial en el cos. A més, es detalla la creació de dues diferents aplicacions per a la visualització del senyal. La primera està dissenyada amb l'aplicació Processing, que genera una interfície gràfica en la pantalla d'un ordinador on es mostra el senyal, amb comunicació serial per l'enviament de dades. La segona està dissenyada amb un marc de treball molt nou anomenat Flutter, que ha permès crear una aplicació amb la mateixa funcionalitat per a dispositius mòbils Android, amb comunicació Bluetooth per la transmissió de dades. S'ha fet ús de la placa Arduino Uno per tal de fer el mostreig del senyal desitjat, ja que porta un ADC incorporat, així com per l'enviament de dades a través del port serial. Per a la comunicació Bluetooth, s'ha utilitzat el mòdul HC-06 conjuntament amb l'Arduino. El prototip final resulta un circuit robust muntat en una PCB i alimentat amb bateries de 9 V, el funcionament del qual es pot trobar representat tan en les dues aplicacions com en l'oscil·loscopi. Paraules clau: Electrocardiògraf, visualització del senyal, Processing, Flutter. Memoria ii Resumen. El trabajo presente en el documento describe todo el proceso involucrado en el diseño y la implementación de un prototipo de electrocardiógrafo para la medida de tres diferencias de bíopotencial en el cuerpo humano. A demás, se detalla la creación de dos distintas aplicaciones para la visualización de la señal. La primera está diseñada con la aplicación Processing, que genera una interficie gráfica en la pantalla de un ordenador donde se muestra la señal, con comunicación serial para el envío de datos. La segunda está diseñada con un marco de trabajo muy novedoso llamado Flutter, que ha permitido crear una aplicación con la misma funcionalidad para dispositivos móviles Android, con comunicación Bluetooth para la transmisión de datos. Se ha utilizado la placa Arduino Uno para hacer el muestreo de la señal deseada, ya que lleva un ADC incorporado, así como también para el envío de datos a través del puerto serial. Para la comunicación Bluetooth, se ha utilizado el módulo HC-06 juntamente con el Arduino. El prototipo final resulta un circuito robusto montado en una PCB y alimentado con baterías de 9 V, el funcionamiento del cual se puede encontrar representado tanto en las dos aplicaciones como en el osciloscopio. Palabras clave: Electrocardiógrafo, visualización de la señal, Processing, Flutter. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. iii Abstract. This paper describes the whole process involved in the design and implementation of a prototype electrocardiograph for the measurement of three bio-potential differences in the human body. In addition, the creation of two different applications for visualizing the signal is detailed. The first is designed with the Processing application, which generates a graphic interface on a computer screen where the signal is displayed, with serial communication for sending data. The second is designed with a very innovative framework called Flutter, which has enabled the creation of an application with the same functionality for Android mobile devices, with Bluetooth communication for data transmission. The Arduino Uno board has been used for sampling the desired signal, as it has a built-in ADC, as well as for sending data through the serial port. The HC-06 module has been used with Arduino for Bluetooth communication. The final prototype results in a robust circuit mounted on a PCB and powered by 9 V batteries, the operation of which can be found represented both in the two applications and on the oscilloscope. Keywords: Electrocardiograph, visualizing the signal, Processing, Flutter. Memoria iv DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. v Agraïments. Primer de tot, donar gràcies a la meva família per recolzar-me durant tot el procés d'estudis, especialment en l'últim tram d'aquests. Vull agrair també als meus amics i companys de la universitat, per haver-me ajudat directament o indirectament, en especial menció al meu gran amic Alejandro, per la guia rebuda quant a termes de programació. Per acabar, agrair al meu tutor Herminio els consells de cada control de seguiment, així com l'oportunitat de poder fer aquest treball. Memoria vi DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. vii Índex. RESUM. _____________________________________________________________ I RESUMEN. __________________________________________________________ II ABSTRACT. __________________________________________________________ III AGRAÏMENTS. _______________________________________________________ V 1. PREFACI. _______________________________________________________ 1 1.1. Origen del treball. .................................................................................................... 1 1.2. Motivació.................................................................................................................. 1 2. INTRODUCCIÓ. __________________________________________________ 3 2.1. Objectius del treball. ................................................................................................ 3 2.2. Abast del treball. ...................................................................................................... 3 3. ORIGEN DE L’ELECTROCARDIÒGRAF I CONCEPTES TEÒRICS. ______________ 5 3.1. L’electrocardiògraf i la seva utilitat. ........................................................................ 5 3.2. Origen de l’electrocardiògraf. .................................................................................. 5 3.3. Estudi de l’estat de l’art. .......................................................................................... 6 3.4. El bio-senyal cardíac. ................................................................................................ 7 3.5. Derivacions estàndards de l’ECG. ............................................................................ 8 3.5.1. Derivacions bipolars clàssiques (DI, DII, DIII). ........................................................ 8 3.5.2. Derivacions unipolars extremitats (aVR, aVL, aVF). ............................................... 8 3.5.3. Derivacions precordials (V1-V6) ............................................................................. 8 3.6. Característiques d’un ECG convencional i representació del bio-senyal. ............... 9 4. DISSENY DEL PROTOTIP A IMPLEMENTAR. ___________________________ 11 4.1. Criteris per a la manipulació i l’aïllament del senyal desitjat. ............................... 11 4.1.1. Amplificació del senyal. ........................................................................................ 11 4.1.2. Pertorbacions i interferències. ............................................................................. 12 4.2. Hardware i software utilitzat. ................................................................................ 14 4.2.1. Hardware. ............................................................................................................. 14 4.2.2. Software................................................................................................................ 19 4.3. Procediments per a l’adquisició del bio-senyal cardíac. ....................................... 22 4.3.1. Col·locació dels elèctrodes. .................................................................................. 22 4.3.2. Pre-amplificació del senyal i circuit impulsat per la cama dreta. ........................ 22 4.3.3. Etapa de filtració del senyal. ................................................................................ 24 Memoria 6 solució salina realitzaven la funció dels elèctrodes. La col·locació dels elèctrodes efectuada es coneix com el triangle d'Einthoven, un en cada braç i l'altre en la cama esquerra [3][6]. Figura 3.2.1. Primer model d’electrocardiògraf d’Einthoven [3]. 3.3. Estudi de l’estat de l’art. Actualment, el model d'electrocardiògraf ha canviat molt respecte al que es pot veure en la figura 3.2.1. S'ha reduït considerablement la seva mida, millorat, i adaptat a les demandes que la medicina ha anat imposant. Avui dia hi ha aparells d'electrocardiografia portàtils a un preu relativament assequible, rellotges intel·ligents que en realitzen, i fins i tot, la seva construcció és una pràctica habitual en estudiants del camp de la bio-enginyeria. Tanmateix, la fiabilitat i les possibilitats d'aquests aparells no són les mateixes que les d'un aparell professional d'hospital. També han sorgit nous tipus d'electrocardiograma a part de l'estàndard, com per exemple, el monitor Holter. Es tracta d'un dispositiu portàtil capaç d'enregistrar els senyals elèctrics del cor del pacient durant un període continu de 24 a 48 hores, mentre aquest fa vida normal. Per altra banda, el monitor d'esdeveniments, que és un aparell també portàtil, però amb un temps d'ús molt més gran que el monitor Holter, on el pacient escull en quin moment d'aquest període de temps vol registrar la seva activitat cardíaca [1]. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 7 3.4. El bio-senyal cardíac. Ara bé, per tal de poder treballar i treure conclusions amb els resultats obtinguts mitjançant l'electrocardiògraf, s'han de conèixer en detall les característiques d'aquest bio-senyal cardíac que estem mesurant. Per començar, aquest senyal és el bio potencial present en la superfície del cos a causa de la polarització i despolarització del cor. Aquests fenòmens tenen lloc dins de les càmeres cardíaques del cor, dues cavitats superiors (aurícules), i dues cavitats inferiors (ventricles) [4]. A continuació, en la figura 3.4.1., es pot observar la forma d'ona típica d'aquest potencial bioelèctric cardíac, com també la definició dels seus intervals. La respectiva amplitud i durada nominals d'aquests intervals es pot trobar en la taula 3.4.1. Figura 3.4.1. Forma d’ona i definició d’intervals típics d’un ECG [4]. Taula 3.4.1. Amplitud i durada nominals dels intervals d’un ECG típic [6]. Amplituds [mV] Duracions [ms] Ona P 0.1-0.3 Interval PR 160 Ona T 0.2-0.3 Interval QT 350 Ona QRS 0.5-3 Segment RR 160 Interval QRS 70-100 Memoria 8 3.5. Derivacions estàndards de l’ECG. Depenent de la col·locació dels elèctrodes en el cos s'obtenen diferents resultats de la mesura de l'activitat elèctrica del cor. Un aparell d'electrocardiografia professional presenta un nombre total de 12 o més mesures diferents (fins a 16) d'aquest senyal. Generalment en són 12, que reben el nom de les 12 derivacions estàndards. Cadascuna d'aquestes mesures presenta unes característiques particulars i diferents de les de la resta de mesures. Per saber-les interpretar correctament és necessari conèixer els seus trets diferencials. 3.5.1. Derivacions bipolars clàssiques (DI, DII, DIII). Aquestes derivacions es tracten de les primeres derivacions descrites per Einthoven (el triangle d'Einthoven), que mesuren els vectors elèctrics des de la perspectiva del pla frontal del cor. Reben aquest nom perquè simplement calculen la diferència de potencial entre dos punts. La derivació DI mostra la diferència de potencial entre el braç esquerre (+) i el braç dret (-), la DII la diferència entre la cama esquerra (+) i el braç dret (-), i la DIII la diferencia entre la cama esquerra (+) i el braç esquerre (-) [5]. Aquestes tres derivacions són les que s'han dut a terme de forma pràctica en aquest treball. 3.5.2. Derivacions unipolars extremitats (aVR, aVL, aVF). Com en el cas anterior, aquestes derivacions mesuren també els vectors elèctrics des de la perspectiva del pla frontal del cor. Però, en aquest cas, no es recull la diferència de potencial entre dos punts, sinó que es calcula el potencial absolut de tres punts respecte a un zero. Aquest zero teòric es tracta del centre del triangle d'Einthoven. Així doncs, les derivacions unipolars en extremitats són les aVR, aVL i aVF, sent aquestes la mesura del potencial en el braç dret, el braç esquerre i la cama esquerra, respectivament. Tot respecte a un zero [5]. 3.5.3. Derivacions precordials (V1-V6) A diferència de les dues classes de derivacions anteriors, aquesta mesura els vectors elèctrics del cor s’efectua des de la seva perspectiva del pla horitzontal. També són unipolars, per tant, mesuren el potencial absolut de determinats punts respecte a un zero. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 9 Aquesta presenta un total de sis mesures diferents. Els potencials absoluts V1 i V2 els trobem en els límits dret i esquerra de l'esternó, respectivament. Per explicar el posicionament del potencial V3 és necessari definir abans la ubicació del potencial V4, situat en la línia imaginaria vertical que passa pel mig de la clavícula. Per tant, el punt V3, es troba en mig de V2 i V4, d'una forma equidistant. Seguidament, trobem V5 en la línia imaginària que passa pel començament de l'aixella, mentre que V6 en la línia imaginària que passa pel mig de l'aixella [5]. Figura 3.5.3.1. Representació gràfica de les derivacions estàndards d’un ECG [5]. 3.6. Característiques d’un ECG convencional i representació del biosenyal. Avui en dia, l'electrocardiograma típic es pot trobar en diversos formats. Hi ha portàtils, de sobretaula, d'ordinador, etc. Pot presentar una elecció manual de les derivacions a mesurar i representar, però l'elecció automàtica és la més estesa. Adquireix i captura d'una a setze derivacions, depenent de la complexitat de l'aparell i de la necessitat. Per a representar totes i cada una de les derivacions descrites en el punt anterior, s'han de seguir unes normes establertes. La reproducció d'aquestes mesures s'efectua sobre un paper quadriculat. Aquestes quadrícules presenten una amplitud i altura d'un mil·límetre. Així doncs, la sensibilitat d'aquests aparells és sovint de 10 mm/mV, de tal forma que per representar 0,1 mV es necessita 1 mm d'altura. No obstant això, aquesta sensibilitat pot prendre els valors de 5 i de 20 mm/mV. Per altra banda, presenten una velocitat d'impressió en el paper de 25 mm/s, on 1 mm horitzontal de paper es correspon a 0,04 s. Aquesta velocitat pot variar entre 10 i 100 mm/s [6]. Memoria 10 Figura 3.6.1. Representació d’un ECG en calibració estàndard [5]. A més, aquests dispositius poden tenir la possibilitat de detectar per ells mateixos arrítmies i de mesurar paràmetres típics del bio-senyal cardíac. Presenten una impedància d'entrada superior a 10 MΩ, un rebuig al mode comú (CMRR) major a 100 dB i un marge freqüencial de treball de 0,05 Hz a alguna freqüència d'entre els valors de 75 i 200 Hz [6]. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 11 4. Disseny del prototip a implementar. El prototip implementat està enfocat a l'obtenció de les tres derivacions bipolars clàssiques. Per tant, encara que s'hagi fet una breu introducció a les 12 derivacions d'un aparell d'electrocardiografia professional, el desenvolupament d'aquest apartat i dels posteriors està dirigit cap al mesuratge en concret d'aquestes tres mesures. 4.1. Criteris per a la manipulació i l’aïllament del senyal desitjat. A l'hora de la captació del bio-senyal cardíac, sorgeixen diverses complicacions degudes a nombrosos factors. Per una banda, la petita amplitud del senyal, imposa com a condició necessària l'existència d'una etapa d'amplificació per a poder treballar amb aquest. Per altra banda, hi apareixen les interferències i pertorbacions, és a dir, tots aquells senyals superposats al senyal d'interès que volem captar. Aquests dos trets s’expliquen en detall en els seus corresponents apartats. 4.1.1. Amplificació del senyal. Per a entendre aquest apartat és necessari disposar d'una visió global del treball. Com es pot constatar en els punts introductoris, l'objectiu del treball és enviar el senyal cap a un dispositiu mòbil. Per fer-ho, es necessita un microcontrolador que sigui capaç de captar aquest senyal i enviar-lo. El microcontrolador escollit és l'Atmega328P-PU, que es troba present en la placa Arduino Uno R3. Aquest i tots els microcontroladors treballen amb valors discrets, com a conseqüència, si es vol operar amb dades analògiques, es necessita un convertidor d'analògic a digital (ADC). El senyal d'interès és un senyal analògic, per aquest motiu es fa ús de l'ADC integrat en la placa Arduino Uno R3. Ara bé, per a fer un bon ús del convertidor i aprofitar tot el seu rendiment, és necessari adaptar el senyal d'entrada als marges superior i inferior d'aquest. Aquí és on entra en joc l'etapa d'amplificació i adaptació del senyal, que té com a objectiu modificar el senyal entrant per tal que aquest comprengui tota l'amplitud de l'ADC. A més, a part de ser necessària l'amplificació per a treballar correctament amb el convertidor ADC, es necessita, ja que és problemàtic treballar amb senyals tan dèbils. Els senyals dèbils tenen una gran predisposició a veure's afectats per resistències internes dels components, entre altres factors que afecten notablement al seu valor. Memoria 12 4.1.2. Pertorbacions i interferències. Encara que en l'etapa de pre-amplificació, explicada més endavant, es produeixi un rebuig al soroll present (CMRR), és a dir, els senyals que s'apliquen al mateix temps en les dues entrades, hi ha senyals indesitjats que encara estan presents. Per eliminar aquestes pertorbacions, primer s’han d'identificar, i després actuar en conseqüència per a reduir-les el màxim possible.  Soroll degut a les línies elèctriques. Considerar el cos humà com una antena, per tant, d’alguna forma capta el senyal present en l’ambient, que és en gran part la tensió en alterna provinent de la línia elèctrica. Figura 4.1.2.1. Exemple de pertorbacions degudes a la línia elèctrica en la mesura d’un senyal [7]. Com s'aprecia en la imatge anterior, hi és present una interferència de tipus més o menys sinusoidal, amb una freqüència de 60 Hz. Per aquesta informació es pot concloure que s'ha realitzat la mesura en Amèrica del nord o en qualsevol altre lloc del món on es faci servir una freqüència de 60 Hz per a l'alimentació de corrent altern. Aquí en Europa, la freqüència d'aquest senyal és de 50 Hz [7].  Soroll electromiogràfic d’alta freqüència. Per altra banda, hi apareixen les pertorbacions que tenen freqüències elevades, com per exemple el soroll muscular d'alta freqüència (soroll electromiogràfic). Aquest és un soroll d’uns 10 kHz de freqüència. Com totes les interferències, embruten el senyal i és necessari la seva eliminació [7]. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 13 Figura 4.1.2.2. Exemple de senyal amb filtre passa baixos a 40 Hz i sense filtrar, amb pertorbacions d’alta freqüència presents [7].  Interferències de baixes freqüències. La interferència deguda a la respiració, així com altres interferències de baixes freqüències, es manifesta com un desplaçament del senyal (offset) a mesurar de forma sinusoidal. Aquesta pren freqüències d’entre 0,15 Hz i 0,3 Hz (de forma aproximada, ja que depèn del pacient)[7]. Figura 4.1.2.3. Exemple de senyal amb filtre passa alts a 0,5 Hz i sense filtrar, amb pertorbacions de baixa freqüència presents [7].  Soroll per mal contacte d’elèctrodes i moviment. Aquest tipus de soroll és degut a les desconnexions entre l'elèctrode i la pell, així com del moviment del pacient. Aquests factors fan variar la impedància entre l’elèctrode i la pell, generant una distorsió en el senyal d’interès [7]. Memoria 14  Soroll electro-quirúrgic. Aquest tipus de pertorbacions són les presents en quiròfans i en aplicacions on s’utilitzen instruments quirúrgics. Presenten una freqüència elevada (100 Hz a 900 Hz) i poden malmetre el senyal mesurat. Per tant, es tracta d’interferències a tenir en compte sempre quan la circumstància ho requereixi [7]. 4.2. Hardware i software utilitzat. Per a fer realitat el prototip presentat en apartats introductoris, es fa ús d’un hardware i d’un software. A continuació es detallen les seves característiques i funcionalitats. 4.2.1. Hardware. En aquest punt es troben els components hardware més rellevants.  Arduino. La placa Arduino Uno Rev3, és una eina fàcil i útil de fer servir, amb una gran quantitat d'informació i recursos disponibles en internet, a la vegada que permet immenses possibilitats. Com a conseqüència, és un dispositiu molt popular entre els amants de la programació i electrònica, des dels principiants fins als més experts. Algunes de les seves característiques més importants són els 14 pins d'entrada/sortida digital, 6 pins per a entrades analògiques, un rellotge intern a 16 MHz a partir d'un oscil·lador de cristall, connexió USB, un rang del voltatge d’entrada recomanat dels 7 als 12 volts, etc. Porta incorporat el microcontrolador de la marca ATMEL, l’Atmega328P, que presenta un convertidor d'analògic a digital de 10 bits, per tant, aquests valors analògics són representats en un rang de 0 a 1023. Aquest ADC té una velocitat de mostreig predeterminada establerta a partir del rellotge intern i d’un prescaler, que és de 125 kHz, un error absolut de precisió de ±2 LSB i un error integral de no linearitat de 0,5 LSB [30][21]. En aquest treball es fa servir per realitzar un mostreig del senyal desitjat, és a dir, capta els valors del senyal analògic cada cert període de temps i realitza la conversió per a produir un senyal discret. També, mitjançant un mòdul Bluetooth, envia el senyal cap al dispositiu mòbil.  Mòdul bluetooth hc-06. Aquest dispositiu permet la connexió Bluetooth entre la placa Arduino i pràcticament qualsevol dispositiu que presenti aquest tipus de xarxa sense fils. Treballa a una freqüència de 2,4 GHz i a una DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 15 velocitat de 9600 Bd. S'alimenta a una tensió d'entre 3,3 i 5 V i té un abast de com a màxim una desena de metres. La seva connexió és senzilla, l'únic a destacar són pels pins de transmissió i recepció. Aquests van cap als pins de recepció i transmissió de l'Arduino, respectivament [9]. Figura 4.2.1.1. Connexionat de l’HC-06 a l’arduino [9]. És utilitzat per proporcionar la connexió sense fils entre el dispositiu mòbil i la placa Arduino.  Elèctrodes. Els elèctrodes utilitzats són de la marca Tiga-Med. Fan la funció d'interfície entre el cos i l’electrocardiògraf, funcionant com a transductors per a convertir el corrent iònic generat pel pacient en energia elèctrica. En concret, es tracta d’elèctrodes de placa metàl·lica, que tenen un conductor metàl·lic en contacte amb la pell, sempre amb l’ajuda de pasta electrolítica. Com es pot apreciar en la figura 4.2.1.2., el model equivalent de l’elèctrode es tracta d’una resistència i un condensador en paral·lel, mentre que la pasta electrolítica es representa com una resistència [10]. Figura 4.2.1.2. Model equivalent de l’elèctrode, la pasta electrolítica, l'epidermis i la dermis amb la capa subcutània [10]. Memoria 22 El seu codi es troba en l’apartat 4.3.5 comentat, i en l’annex B de forma completa. 4.3. Procediments per a l’adquisició del bio-senyal cardíac. Un cop s'ha definit el hardware, el software i els principis a tenir en compte per a la correcta mesura de la diferència dels bio-potencials, es detalla el procediment seguit. 4.3.1. Col·locació dels elèctrodes. Primer de tot, es procedeix a col·locar els 3 elèctrodes que són necessaris. Com es mesuren les derivacions bipolars clàssiques (DI, DII, DIII), es requereix dos elèctrodes que recullen la diferència de bio-potencial entre dues parts del cos i un que es posa en la cama dreta, que farà de referència a massa pel circuit. Els que són col·locats en el braç, se solen ficar en el canell o en la part superior d'aquest, mentre que els de la cama, acostumen a anar entre el turmell i el genoll [17]. Per evitar problemes de soroll relacionats amb el canvi d'impedància entre l'elèctrode i la pell per factors com el moviment, es recomana que el pacient adopti una posició estable i s'asseguri el correcte contacte entre l'elèctrode i la pell, afaitant la zona si es considera necessari. Figura 4.3.1.1. Col·locació elèctrodes segons les derivacions bipolars clàssiques (triangle Einthoven) [17]. 4.3.2. Pre-amplificació del senyal i circuit impulsat per la cama dreta. L’etapa de pre-amplificació del senyal està formada principalment per l’amplificador d’instrumentació, que ha de presentar un seguit de propietats en concret (veure el seu apartat corresponent). És una fase prèvia al filtratge i a l’amplificació, on gràcies a les característiques de l’amplificador d’instrumentació, es produeix un alt rebuig al mode comú (a totes aquelles pertorbacions aplicades d’igual manera en les dues entrades de l’amplificador d’instrumentació), a la vegada que s’amplifica 7 vegades la diferència de bio-potencial de dues parts del cos. En el datasheet DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 23 del component no hi ha el valor exacte del CMRR per a un guany de 7, però si hi és el valor típic d'aquest per a un guany de 10, que és de 110 dB. S'ha escollit aquest valor del guany perquè és el recomanat pel datasheet (veure figura 4.3.2.1.). El circuit impulsat per la cama dreta és una configuració molt recomanada en totes les aplicacions relacionades amb el mesuratge de bio-potecials presents en el cos humà, ja que permet imposar la referència de tensió del cos en el circuit reduint també les interferències en mode comú. S’utilitza un amplificador operacional amb retroalimentació negativa, ja que per culpa de les tensions en mode comú presents en el cos i de la impedància elèctrode-pell, si la connexió es fes directament sense aquesta configuració, hi apareixerien corrents paràsits. La retroalimentació, per tant, redueix aquesta impedància i elimina els corrents paràsits. A més, teòricament, aquesta configuració proporciona al circuit un filtre passa baixos a la vegada que un filtre per a les interferències degudes a la línia elèctrica [31]. El mateix Datasheet del component AD620, mostra un possible front-end per a la implementació d’un equip mèdic d’electrocardiògraf, que és el que s’ha seguit com a referència a l’hora de la implementació d’aquest prototip. Figura 4.3.2.1. Pre-amplificació del senyal i circuit impulsat per la cama dreta amb l’integrat AD620 [11]. La part de l'esquerra del circuit, on hi és l'amplificador operacional AD705J i la seva realimentació negativa, es tracta de l'anomenat circuit impulsat per la cama dreta. El valor del condensador C1 s'escull amb l'objectiu d'aconseguir l'estabilitat d'aquesta retroalimentació, que és de 0,1 µF . El component present en el datasheet per fer aquesta funció és l'AD705J, el qual es tracta d'un amplificador operacional bipolar de baix consum, amb unes propietats idònies per a fer-lo servir en aplicacions combinades amb amplificadors d'instrumentació, integradors de precisió, etc. Malauradament, a causa de la poca disponibilitat d'aquest, s'utilitza el clàssic TL071, que, encara que no presenti uns nivells tan alts d'impedància d'entrada ni tan baixos de corrents i tensions d'offset, compleix amb la funcionalitat. Memoria 24 Seguidament, després del circuit impulsat per la cama dreta hi apareix l’etapa de pre-amplificació del senyal, juntament amb l'ajust del guany de l'amplificador d'instrumentació. Sabent que el guany és 7, es dedueix que el conjunt de resistències equivalents a 𝑅𝐺 (veure Eq. 4.2.1.1.) prenen el valor de 8233,34 kΩ. 4.3.3. Etapa de filtració del senyal. Un cop obtingut la diferència del bio-potencial en l’etapa de pre-amplificació, és necessari l'existència d'una etapa de filtratge. Encara que amb el rebuig al mode comú de l’amplificador d’instrumentació i el circuit impulsat per la cama dreta s'aconsegueixi una reducció considerable de nombroses interferències, continuen havent-hi pertorbacions presents que embruten el senyal. Cal esmentar que el senyal d’interès es troba comprès entre l’interval de freqüències de 0,05/0,67 Hz a 100/150 Hz (100 Hz per adults i 150 Hz per nens) [7]. S’han utilitzat funcions polinomials d’aproximació per al disseny i implementació dels filtres presents en el treball. Aquestes funcions polinomials, depenent de la seva tipologia, poden tenir respostes diferents, com per exemple algunes de les més conegudes com Butterworth, Legendre, Tchebyscheff, Bessel etc. Ara bé, per a escollir quina tipologia de filtre és més adient pel prototip, s’han analitzat les respostes de totes i cada una d’aquestes variants. Un filtre ideal seria aquell que atenués al complet tots aquells senyals amb una freqüència compresa dins de la banda atenuada, i no modifiqués aquells amb una freqüència fora de la banda atenuada. En la pràctica això no és així, hi ha diferents respostes per a un mateix filtre, depenent de la tipologia d’aproximació utilitzada. En la figura 4.3.3.1. es pot observar el comportament real de l’atenuació que proporcionen els diferents tipus de respostes a les diferents freqüències. Es pot observar una clara diferència entre aquests, sent tots filtres passa baixos amb el mateix ordre, amb una atenuació màxima de -3 dB en la banda passant i una freqüència de tall d’1kHz. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 25 Figura 4.3.3.1. Comparativa entre diferents funcions d’aproximació de filtres [18]. Principalment, per a escollir quin tipus de funció polinòmica és més adient, s'ha tingut en compte el comportament de l'atenuació del filtre durant la banda passant, és a dir, durant aquell interval de freqüències on en teoria el filtre no ha d'intervenir. Per exemple, en el cas de la resposta Tchebyscheff o Chebyshev, durant la banda passant, l'atenuació va variant fins a arribar a freqüències on fins i tot aquesta és de -3 dB. Aquests -3 dB d’atenunació es tradueixen de tal forma que 1 V de tensió es redueix fins a 0,707 V. Això no interessa pel treball, ja que les mesures es veurien afectades i no es podrien conèixer els valors reals dels bio-potencials. Per tant, l’opció on el senyal no sofreix cap modificació o pràcticament cap durant les freqüències de pas, es tracta de la resposta Butterworth. Aquest tipus de resposta és l’escollida per al disseny dels filtres passa alts i passa baixos del treball.  Filtre passa alts. S’ha fet ús d’un filtre passa alts per a reduir el màxim possible tots aquells senyals de freqüències baixes superposades al senyal d’interès, com per exemple l’afectació de la respiració. El filtre funciona com a atenuador de tots aquells senyals que estiguin per sota d’una determinada freqüència de tall que s’imposa mitjançant els components del circuit. La freqüència de tall d'aquest filtre típicament oscil·la entre els valors de 0,05 Hz i 0,67 Hz, encara que es recomana el valor de 0,5 Hz, que és el que s'ha utilitzat. Amb aquest valor s'elimina tota aquella interferència que tingui un període de 2 segons en endavant, que és el cas de la respiració humana (sempre que el pacient estigui en posició de repòs i tranquil)[7]. Memoria 26 Un cop escollit el tipus d’aproximació, es procedeix a determinar l’ordre del polinomi. Per conèixer aquest valor, és necessari primer saber quatre paràmetres essencials, tal com es pot veure en la figura 4.3.3.2. Figura 4.3.3.2. Plantilla del filtre passa alts a dissenyar [19]. Coneixent l’atenuació mínima en la freqüència màxima de la banda atenuada (𝐴𝑚𝑖𝑛) que és de -25 dB, l’atenuació màxima en la freqüència mínima de la banda de pas (𝐴𝑚𝑎𝑥), que és de -3 dB i els valors de les freqüències 𝑓 𝐴 i 𝑓𝑃, sent aquestes de 0,119 Hz i 0,5 Hz respectivament, es pot determinar l’ordre amb l’ajuda d’un àbac per a les aproximacions Butterworth. L’ordre n resulta de valor 2. Sabent l’ordre i la tipologia d’aproximació, es fa ús dels circuits presents en la figura 4.3.3.3. Figura 4.3.3.3. Disseny del circuit per a les aproximacions de Butterworth, Legendre i Chebyshev [20]. Al ser un filtre passa alts d'ordre dos, només s'utilitza un bloc de circuit per aconseguir l'aproximació desitjada. És a dir, si es volgués obtenir una aproximació d'ordre quatre, seria necessari la utilització DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 27 de dos d'aquests blocs, i, per ordres imparells, es fa servir l'última columna. No obstant, per trobar els valors exactes del condensador i resistències del circuit, es necessita conèixer els valors dels paràmetres m i q. Aquests estan presents en la taula de la figura 4.3.3.4. Figura 4.3.3.4. Determinació dels paràmetres i de la funció de transferència per a una aproximació de Butterworth [20]. Finalment, cal aplicar l’equació 4.3.3.1., on s’ha imposat el valor d’1µF pel condensador 𝐶𝑜 i, substituint la 𝑤𝑝 per 2𝜋𝑓 𝑝 , sent 𝑓 𝑝 la freqüència de tall (0,5 Hz) es troba el valor corresponent a 𝑅𝑜, que és de 318309,89 Ω. 𝒘𝒑=𝟏 𝑪𝒐𝑹𝒐 (Eq. 4.3.3.1.)[20] Arribat fins aquest punt, només cal substituir els paràmetres en el circuit corresponent de la figura 4.3.3.3. i després normalitzar els valors. El resultat és el següent: Figura 4.3.3.5. Circuit per l’aproximació Butterworth del filtre passa alts dissenyat d’ordre dos. Memoria 28 Per a comprovar que el filtre dissenyat compleix els requisits esperats, s’ha realitzat una simulació del circuit amb els valors dels components utilitzats, en l’aplicació LTspice. D’aquesta manera s’ha conegut el comportament teòric del circuit a diferents freqüències. Es pot apreciar en la figura 4.3.3.6. com a una freqüència de més o menys 0,5 Hz l’atenuació és pràcticament -3 dB. Per altra banda, a 0,119 Hz, hi ha una atenuació gairebé de -25 dB. Per tant, el filtre es comporta segons l’esperat. Figura 4.3.3.6. Resposta en freqüència del filtre passa alts dissenyat.  Filtre passa baixos. S’ha fet ús d’un filtre passa baixos per a reduir el màxim possible tots aquells senyals d’altes freqüències superposades al senyal d’interès, com per exemple les interferències electromiogràfiques. És un atenuador de tots aquells senyals que estiguin per sobre d’una determinada freqüència de tall. La freqüència de tall escollida ha estat de 200 Hz. Amb aquest valor s'elimina tot aquell senyal que tingui un període de 5 ms i més petit. Seguidament, es procedeix a determinar l’ordre del polinomi. Per conèixer aquest valor, és necessari saber els quatre paràmetres essencials, de la mateixa forma que s’ha fet en el cas del filtre passa alts. Coneixent l’atenuació màxima en la freqüència màxima de la banda de pas (𝐴𝑚𝑎𝑥) que és de -3 dB, l’atenuació mínima en la freqüència mínima de la banda atenuada(𝐴𝑚𝑖𝑛), que és de -40 dB i els valors de les freqüències 𝑓 𝑝 i 𝑓 𝐴, sent aquestes de 200 Hz (s’ha deixat marge entre la freqüència de tall i els 100 Hz per no atenuar el senyal d’interès amb total seguretat) i 800 Hz respectivament, es pot DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 29 determinar l’ordre amb l’ajuda d’un àbac per a les aproximacions Butterworth. L’ordre resulta de valor 4. Sabent l’ordre i la tipologia d’aproximació, es fa ús dels circuits presents en la figura 4.3.3.3., però ara dels circuits passa baixos. Al ser un filtre passa baixos d'ordre quatre, és necessari l’ús de dos blocs de circuit per aconseguir l'aproximació desitjada, tal com s’ha explicat anteriorment. Com en el cas anterior, per trobar els valors exactes del condensador i resistències del circuit, es necessita conèixer els valors dels paràmetres m i q. Aquests també estan presents en la taula de la figura 4.3.3.4. Finalment, cal aplicar l’equació 4.3.3.1., on s’ha imposat el valor de 120 nF pel condensador 𝐶𝑜 i, substituint la 𝑤𝑝 per 2𝜋𝑓 𝑝 , sent 𝑓 𝑝 la freqüència de tall (200 Hz) es troba el valor corresponent a 𝑅𝑜, que és de 6631,46 Ω. Arribat fins aquest punt, només cal substituir els paràmetres en el circuit corresponent de la figura 4.3.3.3. i després normalitzar els valors. El resultat és el següent: Figura 4.3.3.7. Circuit per l’aproximació Butterworth del filtre baixos baixos dissenyat d’ordre quatre. Com en el cas anterior, es realitza una simulació del circuit amb els valors dels components utilitzats en l’aplicació LTspice. Observant la figura 4.3.3.8., s’aprecia com a una freqüència de 200 Hz l’atenuació és de -4,2 dB. Per altra banda, a pràcticament 800 Hz, hi ha una atenuació de -49,5 dB. Aquests resultats difereixen lleugerament dels esperats. Això és degut al fet que determinats valors dels condensadors, tot i estar normalitzats, no estaven disponibles. Per tant, s’ha fet ús del valor més proper. No obstant, en la pràctica, el filtre compleix amb la funcionalitat. Memoria 30 Figura 4.3.3.8. Resposta en freqüència del filtre passa baixos dissenyat.  Filtre eliminador de banda. S'utilitza un filtre eliminador de banda per a eliminar les pertorbacions corresponents a la línia elèctrica. A diferència dels dos filtres anteriors, idealment, es tracta d'un filtre capaç d'eliminar només aquells senyals amb una determinada freqüència. En la pràctica, no es pot aconseguir un filtre capaç d'eliminar només els senyals d'una freqüència en concret, sinó que s'elimina un marge de freqüències (aquest marge, com més petit sigui, millor). L'estructura escollida del filtre eliminador de banda rep el nom de filtre notch a partir de cèl·lules en doble T amb millora del factor de qualitat Q. Abans d'explicar en detall aquesta configuració és necessari definir el factor de qualitat Q. Aquest paràmetre representa la relació que hi ha entre la freqüència central del filtre (que és la que es vol eliminar) i el Band Width (que és el marge de freqüències eliminades). 𝑸 = 𝒇𝒐 𝑩𝑾 (Eq. 4.3.3.2.)[23] Una característica molt important del circuit és la possibilitat d’ajustar aquest paràmetre. Per tant, coneixent la freqüència central del filtre, que són els 50 Hz, i el marge de freqüències, sent aquest de 18,59 Hz (40,7 Hz i 59,29 Hz), es pot determinar el valor de la Q = 2,69. S’ha escollit aquest valor de marge i no més petit, ja que per factors com la tolerància dels components, la freqüència central del filtre es podria veure desplaçada i com a resultat el filtre podria no atenuar els senyals amb aquella freqüència a eliminar. D’aquesta manera, encara que hi hagi alguna petita desviació en la 𝑓 𝒐, la DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 31 freqüència desitjada per eliminar té més possibilitats d’entrar en el marge i, per tant, de ser atenuada. Figura 4.3.3.9. Filtre notch a partir de cèl·lules en doble T amb millora del factor de qualitat Q [23]. En la figura 4.3.3.9. es troba la configuració del filtre, on els valors dels condensadors 𝐶1 i 𝐶𝟐 són del mateix valor que 𝐶𝒐, el valor de 𝐶𝟑 de 2*𝐶𝒐 els valors de 𝑅𝟏 i 𝑅𝟐 de 𝑅𝒐 i 𝑅𝟑 de 𝑅𝒐 2. Per trobar 𝐶𝒐 i 𝑅𝒐 es fa ús de l’equació 4.3.3.1., on la 𝑓 𝒐 són els 50 Hz i es fixa el valor de 𝐶𝒐 a 47 nF. D’aquí surt el valor de 𝑅𝒐, que és de 67, 725 kΩ. Ara bé, per trobar el valor de 𝑅𝒀𝒁 i de 𝑅𝑿𝒀 s’utlitza l’equació 4.3.3.3. i 4.3.3.4. 𝑸 = 𝟏 𝟒 ∗ (𝟏 − 𝒎) (Eq. 4.3.3.3.)[23] 𝒎 = 𝑹𝒀𝒁 𝑹𝒀𝒁 + 𝑹𝑿𝒀 (Eq. 4.3.3.4.)[23] Per trobar el valor del paràmetre m es substitueix Q per 2,69, que resulta de valor 0,907. Seguidament, mitjançant l’equació 4.3.3.4., es fixa el valor de 𝑅𝑌𝑍 a 97,5 kΩ per trobar el valor de 𝑅𝑋𝑌, que és de 10 kΩ Com en els casos anteriors, es normalitzen els components i es realitza una simulació en Ltspice amb els components utilitzats. Memoria 38 5. Diagrama de blocs del sistema i prototip implementat. Figura 5.1. Diagrama de blocs del treball. De la imatge anterior, cal comentar que totes les etapes de filtre no es troben seguides pel fet que s’ha anat fent proves a la vegada que s’afegien etapes. És a dir, primerament s’ha estudiat el comportament del prototip amb només el filtre passa alts i, a partir dels resultats, s’han afegit més etapes. És un simple apunt, ja que a efectes pràctics, a l’estar en sèrie, el resultat és exactament el mateix. A continuació, en la figura 5.2, es pot trobar l’esquemàtic del circuit total implementat, que és el que s’ha enviat a fabricar per fer la PCB. Cal destacar que, totes aquelles parts del circuit que tenen el text de “GND”, “v+”, “v-“, “D+”, “D-“, “RL”, “vout”, “v1”, “v2” i “v3”, estan connectades entre si. Figura 5.2. Esquemàtic sencer del prototip. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 39 En la figura 5.3. primerament, es troben els “headers”, que s’utilitzen per a l’alimentació i la connexió a massa del circuit, per a l’entrada dels bio-potencials del cos i també per al senyal de sortida. Seguidament, hi apareix el circuit impulsat per la cama dreta juntament amb l’etapa de preamplificació. Figura 5.3. Primera part de l’esquemàtic sencer del prototip. Començant per la part esquerra de la figura 5.4. es pot trobar el filtre passa alts, seguit de l’etapa d’amplificació i, finalment, el filtre passa baixos d’ordre 4. Figura 5.4. Segona part de l’esquemàtic sencer del prototip. Començant també per la part esquerra de la figura 5.5. es pot trobar el filtre eliminador de banda seguit del divisor de tensió amb el circuit sumador, que formen part de l’etapa d’adequació del senyal. Memoria 40 Figura 5.5. Tercera part de l’esquemàtic sencer del prototip. Com s'ha comentat anteriorment, aquest circuit és l'implementat en PCB, tal com es pot veure en la figura 5.6. Presenta dues capes i unes dimensions de 86 mm*58 mm, amb un espai màxim entre connexions de 0,16 mm. Aquelles connexions corresponents a l'alimentació i a massa tenen una amplada de 0,5 mm, mentre que la resta de connexions de 0,254 mm. Figura 5.6. Esquemàtic PCB del prototip. Finalment, en la figura 5.7, es pot veure el resultat final de la PCB amb tots els components soldats. Ha estat dissenyat en EasyEDA [32] i enviat a construir a JLPCB [33]. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 41 Figura 5.7. Prototip final en PCB. La connexió de l'Arduino amb el mòdul Bluetooth HC-06 s'ha fet de manera externa a la PCB, d'igual forma que l'alimentació. Ha sigut necessari connectar el negatiu d'una pila amb el positiu de l'altra, per generar els +9 V i els -9 V. Memoria 42 6. Funcionament, disseny i programació de l’aplicació mòbil. A continuació, s’explica el funcionament de l’aplicació mòbil a la vegada que el codi que ho fa possible. Cal Remarcar que, a l’hora de crear un projecte Flutter en Android Studio, es creen nombroses carpetes i fitxers, però aquí només s’explica aquells que s’han modificat i en són útils de forma directa. Figura 6.1. Fitxers de l’aplicació Flutter en Android Studio. Per seguir un fil conductor a l'hora d'entendre el codi, es comença explicant la programació del "main.dart", que conté el "bucle" principal de l'aplicació. Aquest bucle executa el widget sense “estat” “MyApp”. Aquest s’encarrega d’iniciar l’aplicació, on primer de tot, se sol·liciten els permisos necessaris al dispositiu, fent ús del paquet “permission_handler” [35] (tots aquells referents als Bluetooth i d'altres que es necessiten indirectament). Seguidament es redirigeix cap al widget "LandingPage"amb l’ajuda de rutes [36] (que és el widget que construeix la pantalla inicial). Aquest és present en “LandingPage.dart”. Molt d'aquest correspon a l’interfície gràfica, per tant, no es comenta amb detall (és una finestra que no canvia, no té "estat"). Si cal esmentar que, en polsar el botó d'aquesta pàgina inicial ("Connect device"), es navega cap al widget "MyApp" un altre cop perquè s'executi una funció. Aquesta funció, que és de tipus “builder”, amb l'ajuda d'un "Stream" (que és com una variable que s'encarrega de guardar els estats canviants DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 43 del Bluetooth, i "avisa" a la funció que s'han produït canvis), és l'encarregada de redirigir el codi cap a una determinada finestra (widget), depenent si el Bluetooth es troba activat o no (aquest “Stream” està sempre controlant l’estat del Bluetooth). Si el Bluetooth està activat, es redirigeix cap al widget "DispDevicesScreen" (present en la "page" "FindDevicesScreen.dart") i, si no està activat, es redirigeix cap al widget "BluetoothOffScreen" (present en la "page " "BluetoothOffScreen.dart" [26]. Les instruccions Bluetooth (de la llibreria "flutter_blue.dart") i la seva estructuració, s'han tret d'un exemple oficial present en el repositori oficial de paquets per a les aplicacions Dart i Flutter [26]. Ara bé, tal com s'ha explicat, quan el Bluetooth és apagat i s'ha polsat al botó "Connect device" de la pantalla inicial (widget "LandingPage"), s'executa el widget "BluetoothOffScreen". Aquest widget simplement crea una pantalla d'espera on es mostra un petit text, tampoc té "estat". El widget "DispDevicesScreen", pren un paper molt important en el funcionament. Cal anomenar que, al ser la pantalla on s'aniran mostrant els diferents dispositius Bluetooth disponibles, es crea un "estat" en el widget, que permet actualitzar la pantalla a mesura que hi ha nous dispositius. Es crea també un “stream” per rebre resultats dels disposotius Bluetooth i també avisar a mesura que es van trobant (“_streamSubscription”), així com també una llista buida per poder emmagatzemar aquests resultats (“_results”). Seguidament, es crida a la funció “initState()” on mitjançant “startDiscovery()” i “.listen((result)” es realitza una primera subscripció per rebre els resultats provinents del Bluetooth i s’emmagatzemen els resultats en la variable ("result"). A continuació, es busca en la llista “_results” si l’adressa del dispositiu nou trobat ja es troba dins de la llista. Si es troba en la llista, simplement s’actualitza la informació i, si no està, s’afegeix mitjançant “_results.add(result)”. Quan ja no es detectin nous dispositius, es deté la cerca (“_isDiscovering = false;”). Seguidament, amb la instrucció ".map", es fa una iteració sobre tots els dispositius "result" presents en “_results”, i s'envia la seva informació (de tots els dispositius captats, d’un en un) cap a un widget que crea la seva visualització en pantalla. Aquest widget rep el nom de "BluetoothDeviceListItem", que es troba dins de la carpeta "components", amb el mateix nom. Aquest widget, a part de crear la visualització d’un rectangle amb el nom del dispositiu, genera un botó a la dreta "CONNECT". Quan es polsa, es redirigeix cap a la "Page" "FindDevicesScreen.dart" (que és on estàvem abans, fent ús de la funció “onTap”), i s'executa una navegació cap al widget "DeviceScreen"[36], amb el "device" seleccionat com a argument (del qual s’ha polsat el seu botó), que conté tota la seva informació (“builder: (context) => DeviceScreen(device: result.device)”). En aquesta mateixa pantalla, a baix a la dreta, hi apareix un botó. Aquest botó, amb l’ajuda de “_isDiscovering” va variant entre un senyal d’”stop” quan la cerca de dispositius bluetooth està activa Memoria 44 (malgrat això, en aquest moment el botó no té cap acció) i entre un senyal de “buscar” quan la cerca de dispositius està inactiva. En aquest moment el botó sí que presenta acció, si es pren s’executa la funció “_StartScan” que inicia la cerca de dispositius. El widget "DeviceScreen" és a la "page" amb el mateix nom. Aquesta pantalla executa la funció principal de l'aplicació, rebre les dades enviades pel dispositiu Bluetooth al qual s'ha connectat i grafia les dades en un gràfic. Per tant, es tracta d'una pantalla que té un "estat". Primerament, es crea una variable (“_connection”) per controlar la connexió amb el dispositiu, i un “Stream” per controlar la “subscripció” a aquest per rebre dades(“_dataSubscription”). Seguidament, es fa el protocol "bonding" que verifica si el dispositiu seleccionat ha estat prèviament vinculat, si no ho ha estat realitza el procés de vinculació. Un cop fet aquest protocol, ja es pot establir la connexió. És un protocol totalment necessari abans de connectar-se al dispositiu. És una acció que es pot dur a terme gràcies al paquet “flutter_bluetooth_serial” [27]. Dins de la funció “_connectToDevice()” es realitza la subscrició per rebre les dades, on mitjançant ".listen", es reben les dades provinents del Bluetooth i s’emmagatzemen en “data”. Aquestes dades han de ser transformades per poder-se grafiar. Primer es converteix a "string" i després a un valor enter. En acabat, amb l’ajuda del paquet “_chartData”[29], es grafien els punts X i Y i amb “SfCartesianChart” es dibuixen els eixos del gràfic. Entrant més en detall, observant el codi, es pot veure com no s'accepta cap dada més petita a 100, que correspon a 0,489 V (es pot veure en les figures 7.1.1, 4.3.4.4. i 7.1.2. com cap senyal arriba fins a tal límit). Per tant, en rebre una dada més petita a 100, no s'actualitza el valor de la Y sinó que es grafia el valor de la Y anterior. Això és degut al fet que a vegades, els valors que es reben per Bluetooth, presenten valors molt baixos de forma aleatòria i sense sentit. D'aquesta manera es corregeix el problema i el procés de grafiar no s’atura. Figura 6.2. Valors rebuts per Bluetooth (problema d'incoherència dades). A més, cada vegada que es rep una dada (mitjançant la funció “print”, s’observa com totes les dades rebudes per Bluetooth són vàlides, per tant, sempre s’hauria de grafiar el valor de la Y i de la X), sigui més petita que 100 o no, se suma una unitat a la variable X (que actua com a temps). Les dades s'actualitzen quan el valor de X arriba a 1000, que coincideix també quan el gràfic arriba més o menys al seu límit en X (1030), i dura aproximadament 5,5 segons. Per tant, això vol dir que s'estan realitzant impressions en el gràfic 181,81 vegades /segon (ja que es triga 5,5 segons en grafiar 1000 valors). De forma similar al que ocorre amb l'aplicació de Processing, s'ha de modificar la freqüència de mostreig DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 45 de l'Arduino per a una millor visualització del senyal. En aquest cas, la freqüència idònia és de 153,85 Hz. Cal esmentar que en el repositori oficial de paquets per a les aplicacions Dart i Flutter, s'ha trobat informació molt útil sobre com utilitzar la llibreria "flutter_bluetooth_serial.dart"[27], a més, s'ha trobat un exemple en aquesta mateixa pàgina on hi ha un codi que rep dades per bluetooth i les grafia [28]. Per saber com crear un gràfic, s'ha fet ús de la informació disponible en el mateix repositori, però per la llibreria "syncfusion_flutter_charts" [29]. El codi de "main.dart" i el present dins les carpetes de "pages" i "components", corresponent al que s’ha explicat (s’ha estructurat d’aquesta forma perquè sigui més intuïtiu) es pot trobar en l'Annex A, comentat al màxim detall per a una major comprensió. S'ha explicat l'estructura principal i més important de l'aplicació, però hi ha carpetes i codis que també són necessaris per al correcte funcionament d'aquesta. Per exemple, per fer ús de llibreries, és completament necessari tenir-les descarregades i ficades en un arxiu anomenat "pubspec.yaml". A més, en aquest arxiu també s'ha d'afegir una instrucció per tal de poder ficar imatges en l'aplicació (com és el cas de la imatge i dels dos objectes en la pantalla d'inici)[37]. També és necessari ficar tots aquells permisos que se sol·liciten en el dispositiu mòbil en un arxiu anomenat "AndroidManifest.xml" [35] que es troba dins de la carpeta "android". Per acabar, indirectament s'ha fet ús del codi present en la carpeta "Styles", on simplement es descriu breument la família tipogràfica o color al qual algun text del codi de l'aplicació ha fet referència. Figura 6.3. Interfície de la pantalla inicial de l’aplicació. Memoria 46 Figura 6.4. Interfície de la pantalla on es mostren els dispositius Bluetooth a condició que el Bluetooth estigui actiu. En l'esquerra la cerca està activa, mentre que en la dreta ja s'ha aturat. Figura 6.5. Interfície de la pantalla que es mostra quan el dispositiu Bluetooth està desactivat i s’ha polsat el botó “Connect device” de la finestra inicial. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 47 Figura 6.6. Interfície de la pantalla de visualització de dades en vertical. En l'eix horitzontal no s'ha especificat que les unitats de "Time" siguin segons, ja que realment l'eix horitzontal no està construït a partir del temps, sinó que són simplement divisions de la pantalla. Figura 6.7. Interfície de la pantalla de visualització de dades en horitzontal. Cal comentar que la fletxeta cap enrere present en les figures no s’ha creat directament, sinó que és una implementació del widget “AppBar”. Aquest widget genera per defecte aquest símbol que si es pren sobre ell es navega cap a la ruta anterior que té guardada el programa [34]. A més, de forma automàtica, la mateixa aplicació intenta adaptar els widgets de cada finestra quan el telèfon mòbil es col·loca en horitzontal. En l'app del treball es pot fer en totes les pantalles menys en la inicial, on no hi ha cap instrucció per tal de poder navegar de dalt cap a baix (“SingleChildScrollView”) i, per la configuració de la pantalla, canviant els eixos horitzontal i vertical sobresurt el contingut d'aquesta. Memoria 54 En la figura 7.3.1. es pot observar el senyal corresponent a la I derivació bipolar clàssica en l’aplicació d’ordinador Processing. Tenint en compte que el valor màxim de l’amplitud del senyal present és d’aproximadament 1,5 V, es pot deduir l’amplitud del senyal original, que resulta de més o menys 1 mV Figura 7.3.2. Resultat II Derivació en l’aplicació Processing. En la imatge anterior es pot observar el senyal corresponent a la II derivació bipolar clàssica en l’aplicació d’ordinador Processing. Tenint en compte que el valor màxim de l’amplitud del senyal present és d’aproximadament 4,2 V, es pot deduir l’amplitud del senyal original, que resulta de més o menys 2,8 mV Figura 7.3.3. Resultat III Derivació en l’aplicació Processing. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 55 En la figura anterior es pot observar el senyal corresponent a la III derivació bipolar clàssica en l'aplicació d'ordinador Processing. Tenint en compte que el valor màxim de l'amplitud del senyal present és d'aproximadament 2,5 V, es pot deduir l'amplitud del senyal original, que resulta de més o menys 1,67 mV. En aquest cas, els valors de l'amplitud màxima comparada amb l'obtinguda amb l'oscil·loscopi disten notablement, fins i tot a més de 0,5 mV de diferència. Tot i això, les formes d’ona són similars, el senyal es distingeix clarament i, com en l’oscil·loscopi i en l’app mòbil, els valors de les amplituds de l’ona QRS entren dins de la normalitat de valors establerts en la taula 3.4.1. D'igual manera que ocorre en l'app mòbil, en la II i III derivació hi apareix el senyal superposat a un seguit d'interferències i pertorbacions. Aquestes dues mesures tenen més predisposició a veure's afectades. Encara que el senyal representat en les dues aplicacions sigui nítid, no és tan clar com aquell visualitzat en l'oscil·loscopi. Això pot ser causa de petits errors o limitacions a l'hora de convertir el senyal per part de l'ADC, errors o limitacions presents en la comunicació (sigui comunicació serial o mitjançant Bluetooth), per qüestions de codi de cada programa o a la seva velocitat a l'hora de grafiar les dades. Memoria 56 Conclusions. Per concloure, es fa una valoració dels resultats obtinguts, de les problemàtiques solucionades, d'algunes encara presents juntament amb la seva possible millora en un futur i, per acabar, una anàlisi general del treball. Com s'ha pogut veure en tot el treball, s'ha aconseguit mesurar tres diferències de bio-potencial en el cos humà amb una quantitat de pertorbacions mínima. Tanmateix, Els resultats visualitzats en l'oscil·loscopi presenten un senyal més nítid (quasi perfecte) que els representats en les dues aplicacions. Encara que s'hagi experimentat amb el codi d'aquests dos programaris (fent-lo més eficient) i amb la freqüència de mostreig de l'Arduino per a aconseguir millors resultats, de cap forma s'assoleix un senyal tan nítid com en l'equip del laboratori. Ara bé, s'ha de tenir present que el convertidor analògic-digital de l'Arduino pot presentar diverses errades d'imprecisió a l'hora de fer la conversió. Al cap i a la fi, no es tracta d'un aparell professional dedicat al mostreig i representació de senyals, a diferència de l'oscil·loscopi. Una possible millora de cara al futur del treball podria ser incorporar un dispositiu de mostreig professional, a la vegada que millorar la comunicació entre el dispositiu amb el telèfon mòbil i també amb l’ordinador. També millorar el codi de cada una d’aquestes dues aplicacions per tal d'obtenir un resultat encara més pròxim al de l’oscil·loscopi. Segons el teorema de Nyquist, la freqüència de mostreig hauria de ser de 200 mostres/segon, però amb aquest valor, apareixien incongruències en els resultats del senyal en les aplicacions. Per tant, malgrat l'incompliment d'aquesta norma, les freqüències de mostreig que proporcionen un resultat òptim són de 100 mostres/segon i de 153 mostres/segon per l'aplicació de Processing i per la del mòbil, respectivament. A més, tenint en compte que tant per comunicació serial com per Bluetooth no es reben valors invàlids (s'ha comprovat fent "print" dels valors), sabent les divisions en horitzontal de la pantalla de visualització i el temps aproximat que triga el senyal a recórrer aquesta, es pot determinar la velocitat a la qual s'està grafiant. Aquesta velocitat d'impressió resulta de 53 punts/segon en el cas de l'aplicació de Processing, i de 181 punts/segon en el cas de l'aplicació mòbil. Un altre aspecte de millora podria ser un estudi més profund sobre que és el que està passant, per tal d'aconseguir fer el mostreig del senyal a la velocitat desitjada sense inconvenients, així com grafiar el senyal a la mateixa velocitat que es fa el mostreig. El prototip és robust, està presentat en PCB i té una sensibilitat molt alta. Aquesta sensibilitat, necessària per captar els ínfims senyals, presenta alguns inconvenients, ja que per a la correcta mesura de les derivacions, s'ha d'anar amb compte amb el cablejat sortint de les extremitats del cos. El més petit contacte o mal posicionament afecten notablement al senyal. També afecta molt la posició del pacient, aquest ha d'estar relaxat el màxim possible, pel fet que com s'ha comentat, DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 57 qualsevol detall té un impacte directe en el senyal. En un futur, es podria dotar al prototip d'un cablejat professional completament protegit contra tota mena d'interferències i de contactes. Destacar que el prototip presenta un senyal més net en la I derivació (comparat amb la II i III), pel que fa als resultats visualitzats en les aplicacions. En l’oscil·loscopi, aquest problema no és tan remarcable. En definitiva, el prototip d'electrocardiògraf conjuntament amb l'aplicació mòbil no dista gaire d'un aparell d'electrocardiografia comercial, i el funcionament de l'aplicació d’ordinador Processing compleix amb la seva comesa. Tanmateix, si es volgués comercialitzar, s'haurien de solucionar els aspectes abans esmentats, així com la incorporació d’una bateria integrada i no externa, augmentant així la seva practicitat. DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 59 Pressupost i/o Anàlisi Econòmica. A continuació, s’inclou el pressupost referent als materials utilitzats, cost d’enginyeria i mà d’obra. Tots els programaris que s’han fet us són de lliure disposició. Material utilitzat directament. Taula Pressupost.1. Taula del pressupost final del material utilitzat directament. Material Preu Unitat (€/u.) Quantitat (u.) Total (€) Total (€) amb IVA Arduino UNO 19,83 1 19,83 23,95 HC-06 8,26 1 8,26 9,99 Cable bateria-Arduino 5,78 (€/10 u.) 10 5,78 6,99 AD620 5,74 1 5,74 6,95 TL071 0,75 1 0,75 0,91 TL074 0,72 2 1,44 1,74 Headers 6,27 (€/50 u.) 50 6,27 7,59 Resistències 1 MΩ 0,04 5 0,2 0,24 Resistències 10 kΩ 0,03 5 0,15 0,18 Resistències 24,9 kΩ 0,04 5 0,2 0,24 Resistències 8,25 kΩ 0,04 5 0,2 0,24 Resistències 226 kΩ 0,02 5 0,1 0,12 Resistències 453 kΩ 0,03 5 0,15 0,18 Resistències 220 kΩ 0,02 5 0,1 0,12 Resistències 6,65 kΩ 0,04 5 0,2 0,24 Memoria 60 Resistències 68,1 kΩ 0,04 10 0,4 0,48 Resistències 34 kΩ 0,03 5 0,15 0,18 Resistències 97,6 kΩ 0,04 5 0,2 0,24 Resistències 2 kΩ 0,03 5 0,15 0,18 Condensadors 0,1 µF 0,03 5 0,15 0,18 Condensadors 1 µF 0,79 2 1,58 1,91 Condensadors 22 nF 0,3 1 0,3 0,36 Condensadors 100 nF 0,59 3 1,5 1,82 Condensadors 333 nF 0,3 1 0,3 0,36 Condensadors 47 nF 0,39 6 2,34 2,83 PCB 1,52 (€/5 u.) 5 1,52 1,84 Cables ECG 15,69 (€/7 u.) 7 15,69 18,99 Elèctrodes 8,26 (€/50 u.) 50 8,26 9,99 Bateries 9 V 14,77 /(€/2 u.) 2 14,77 17,87 Total amb IVA 114,73 € Material utilitzat indirectament. Taula Pressupost.2. Taula del pressupost final del material utilitzat indirectament. Material Preu Unitat (€/u.) Quantitat (u.) Total (€) Total (€) amb IVA Portàtil ASUS 495,86 1 495,86 599,99 Soldador elèctric 16,16 1 16,16 19,55 DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 61 Estany 4,95 1 4,95 5,99 Oscol·loscopi TDS1002B 192,17 1 192,17 232,52 Mòbil xiaomi 147,36 1 147,36 178,3 Total amb IVA 810,78 € Cost d’engingyeria. Taula Pressupost.3. Taula del pressupost final del cost d’enginyeria. Concepte Preu per hora (€/h) Quantitat (h) Total (€) Total (€) amb IVA Enginyer 10,75 450 4837,5 5853,38 Total amb IVA 5853,38 € Balanç total. Taula Pressupost.4. Taula del balanç total final. Concepte Total (€) amb IVA Material utilitzat directament 114,73 Material utilitzat indirectament 810,78 Cost d’enginyeria 5853,38 Total amb IVA 6778,89 € DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 63 Bibliografia. [1] Mayo Clinic. Electrocardiograma (ECG) [en línia]. Consultat el 14 de març de 2023. Disponible a: https://www.mayoclinic.org/es-es/tests-procedures/ekg/about/pac-20384983 [2] American Heart Association. Electrocardiogram (ECG or EKG) [en línia] . Consultat el 14 de març de 2023. Disponible a: https://www.heart.org/en/health-topics/heart-attack/diagnosing-a-heartattack/electrocardiogram-ecg-or-ekg [3] Pfizer. Flashback: The First ECG [en línia]. Consultat el 17 de març de 2023. Disponible a: https://www.pfizer.com/news/articles/flashback_the_first_ecg [4] Universitat de València (Escola Tècnica Superior d’Enginyeria). Tema 2 Bioseñales. Consultat el 19 de març de 2023. Disponible a: http://ocw.uv.es/ingenieria-y-arquitectura/15/ib_material/IB_T2_OCW.pdf [5] Universitat Jaume I (Facultat de Ciències de la Salut). Tema 2: Fundamentos básicos electrocardiografía. [fitxer pdf] [6] Universitat Politècnica de Catalunya, Centre de Recerca en Enginyeria Biomèdica.Tema 2: Sistemas de medida de biopotenciales. [fitxer pd]. [7] Richard E. Gregg MSEE, Sophia H. Zhou PhD, James M. Lindauer MD, Eric D. Helfenbein MSEE, Karen K. Giuliano RN, PhD. What is inside the electrocardiograph?. Publicat el 14 d’Agost de 2008. ScienceDirect. [8] Leydy Laura Álvarez E. Análisis de esquemas de filtrado análogo para señales ECG. Publicat en Desembre de 2007. Universitat Tecnològica de Pereira. [9] Naylamp Mechatronics. Tutorial básico de uso del módulo Bluetooth HC-06 y HC-05 [en línia]. Trujillo, Perú: Naylamp Mechatronics, 2019. Consultat el 29 de març de 2023. Disponible a: https://naylampmechatronics.com/blog/12_tutorial-basico-de-uso-del-modulo-bluetooth-hc-06-yhc-05.html [10] Ronald Del Aguila. Electrodos para medir biopotenciales. Consultat el 30 de març de 2023. Disponible a : https://studylib.es/doc/7213959/electrodos-para-medir-biopotenciales [11] Analog Devices. AD620 Instrumentation Amplifier Datasheet [document tècnic]. Disponible a: https://pdf1.alldatasheet.es/datasheet-pdf/view/48090/AD/AD620.html Annexos 70 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 senyal en temps real', style: TextStyle( decoration: TextDecoration.none, ), ), ], ), maxLines: 7, overflow: TextOverflow.ellipsis, ), SizedBox(height: 20,), TextButton( //crea un botó style: ElevatedButton.styleFrom(//permet configurar-lo shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),//estableix el radi del borde del rectangle backgroundColor: Colors.black,//estableix el fons a negre minimumSize: Size.fromHeight(50),//50 px d'altura ), onPressed: (){ Navigator.pushNamed(context, '/findDevices'); },// navega cap '/findDevices'ruta //quan es presioni el botó. Es "navegarà" fins a "/findDevices" child: const Text( //les característiques del text del botó "Connect device", maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( color: Colors.white, fontStyle: FontStyle.normal, fontWeight: FontWeight.w700, fontSize: 25), ) ) ], ), ) ], ) ), ); } } class LandingBackground extends StatelessWidget { //defineix fons de pantalla final Widget child; //aquest child és él widget que s'ha definit abans final Size size; //és la variable definida anteriorment const LandingBackground({ //agafa aquestes propietats i les asigna a les variables Key? key, required this.size, required this.child }) : super(key: key); @override Widget build(BuildContext context) { return Container( //"contenedor" principal del fons DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 71 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 height: size.height, //ocupa tota la altura vertical width: double.infinity, //ocupa tota la amplada disponible child: Stack(//serveix per ficar widgets uns asobre d'altres alignment: Alignment.center, children: <Widget> [ Positioned(//permet ubicar de forma concreta un widget top: 0, //en el cantó esquerre superior left: 0, child: Image( image: const AssetImage( 'assets/images/main_top.png' //el mateix que l'altre imatge ), width: size.width * 0.3, ) ), Positioned( bottom: 0, //en el cantó esquerre inferior left: 0, child: Image( image: const AssetImage( 'assets/images/main_bajo.png' ), width: size.width * 0.2, ) ), SafeArea( //s'utilitza per a que tot el contingut de "Landingbackground estigui //dins del marge child: Center(//en la última capa, s'executa aquesta funció per tal de centrar //tot el contingut de la pantalla. child: child, ) ) ] ) ); } } A3. Codi “BluetoothOffScreen.dart”. 1 2 3 4 5 6 7 8 import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key}) : super(key: key); //venim aquí desde la funció main() quan el bluetooth està desconnectat @override Widget build(BuildContext context) { Annexos 72 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 return Scaffold(//per crear estructura d'una pantalla appBar: AppBar( title: Text('Check your connection'), ), backgroundColor: Colors.lightBlue, body: Center( child: Column( //col·loca el text un abaix d'un altre mainAxisSize: MainAxisSize.min,//per utilitzar el mínim espai possible children: <Widget>[ const Icon( Icons.bluetooth_disabled,//biblioteca materialdart size: 200.0, color: Colors.white54,//color blanc amb opacitat del 54% ), Text( 'Bluetooth is disconnected.', style: Theme.of(context) .primaryTextTheme//estil de text del paquet material.dart .titleMedium //estil de text del paquet material.dart ?.copyWith(color: Colors.white), //instrucción requerida por style ), Text( 'Please, turn on your bluetooth on device settings.', style: Theme.of(context) .primaryTextTheme .titleMedium ?.copyWith(color: Colors.white), ) ], ), ), ); } } A4. Codi “FindDevicesScreen.dart”. 1 2 3 4 5 6 7 8 9 10 11 12 import 'dart:async'; //Paquet async que proporciona funcions asíncrones com "StreamSubscription" import 'package:flutter/cupertino.dart';//widgets de decoració import 'package:flutter/material.dart';//més widgets de decoració import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; //importa el paquet "flutter_bluetooth_serial". Biblioteca que permet nombroses interaccions //i funcionalitats mitjançant Bluetooth import '../components/BluetoothDeviceListItem.dart';//importa l'arxiu amb el nom especificat, //que es troba dins la carpeta components del projecte import 'DeviceScreen.dart';// El mateix que l'anterior. class DispDevicesScreen extends StatefulWidget {//es defineix DispDevicesScreen com a DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 73 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 //widget amb estat @override _DispDevicesScreenState createState() => _DispDevicesScreenState();//crea l'estat DispDevicesScreenState //, aquest estat s'encarrega de gestionar els canvis en la pantalla (del widget DispDevicesScreen) } class _DispDevicesScreenState extends State<DispDevicesScreen> {//_DispDevicesScreenState és una extensió //de l'estat de la pantalla DispDevicesScreen List<BluetoothDiscoveryResult> _results = [];//llista d'objectes que emmagatzemarà els resultats //de buscar dispositius bluetooth. <BluetoothDiscoveryResult> és una classe de variable //gràcies a la llibreria flutter_bluetooth_serial bool _isDiscovering = false;//indica si s'està fent la cerca de dispositius bluetooth //En aquest cas, indica que no s'està realitzant la búsqueda //més endavant, es definirà com a true per indicar que si s'està fent StreamSubscription<BluetoothDiscoveryResult>? _streamSubscription; //es crea un stream _streamSubscription //de tipus tot el que hi ha a la esquerra. Controla resultats búsqueda dispositius Bluetooth //el ? es perque pot ser positiva o negativa el stream @override//permet sobreescriure la funció initState, que ja existeix ja que //_DispDevicesScreenState es una extensió de State, i aquest State porta incorporat initState void initState() { //el codi es sitúa aquí automàticament quan s'inicía _DispDevicesScreenState super.initState(); _startScan();//Per tant, s'afegeix _startScan sind de la funció initState, ja que aquesta //s'executa sempre. } @override void dispose() {//s'utilitza aquest mètode per finalitzar la tasca de buscar disp bluetooth //es crida aquesta funció quan el widget "-DispDevicesScreenState" ja no està en vigor //com per exemple quan es canvia de pàgina. _streamSubscription?.cancel();//es cancel·la la subscripció per rebre dispositius super.dispose(); } void _startScan() { setState(() { //canvia l'estat de _DispDevicesScreenState _results.clear();//buida tota la llista de resultats anteriors _isDiscovering = true; //es comença amb l'escaneig dels dispositius Bluetooth }); _streamSubscription = //variable de tipus "StreamSubscription" que emmagatzemarà la informació //dels resultats de la exploració Bluetooth. startDiscovery i .listen es fa la Primera subscripció FlutterBluetoothSerial.instance.startDiscovery().listen((result) { //Es crida a startDiscovery //per iniciar la exploració de dispositius Bluetooth. Estructura que es pot trobar en l'exemple //aquest mètode retorna un "stream" que emet events cada cop que es detecten dispositius setState(() {//serveix per realitzar canvis en l'estat del widget "_DispDevicesScreenState" final existingIndex = _results.indexWhere(//serveix per trobar l'índex (posició) d'algún //element que compleixi amb la següent condició (element) => element.device.address == result.device.address);//es fa una iteració // per veure si la direcció del dispositiu actual (que es result, tal i com s’ha ficat en .listen) //coincideix amb algun element de la llista if (existingIndex >= 0) //si s'ha trobat algún element que compleix la condició _results[existingIndex] = result; //s'actualitza la informació perque ja estaba else Annexos 74 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 _results.add(result);//s'afegeix el nou dispositiu a la llista _results }); }); _streamSubscription!.onDone(() {//quan ja no hi hagin més elements en el "stream" de //"_streamSubstription, s'activa aquest "flag" setState(() { _isDiscovering = false;//es finalitza la búsqueda de dispositius }); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Find Devices'), ), body: RefreshIndicator( //widget que permet, lliscant cap abaix la pantalla, //redireccionar cap a la funció _startScan per tornar a buscar dispositius onRefresh: () async {//en la pràctica, esperar fins a que ja no es detectin més //dispositius per fer-ho _startScan(); }, child: SingleChildScrollView(//permet navegar verticalment per a veure més contingut //quan el contingut excedeix de la pantalla child: Column( children: _results.map((result) {//"map" permet iterar entre cada element. return BluetoothDeviceListItem(//es crea un nou ítem (però això es troba en "components", "BluetoothDeviceListItem" // al que enviem la informació de bluetooth del dispositiu actual. El widget que fa això, es troba dins de la //carpeta de components device: result.device,//fiquem la informació del aparell en device, i és aquesta informació la que s'utlitza //per a crear el Item en la seva "page" corresponent onTap: () {//al polsar sobre el botó que es crea en "BluetoothDeviceListItem" Navigator.of(context).push(//aquestes línies serveixen per a navegar fins a la pantalla //DeviceScreen, tenint el disposotiu seleccionat com a "argument" MaterialPageRoute( builder: (context) => DeviceScreen(device: result.device),//aleshores, //es mostra la pantalla de DeviceScreen amb el device específic que s'hagi seleccionat //realment es crea un ítem per cada dispositiu, per tant quan polsem sobre el seu respectiu botó //el device seleccionat serà el botó del que s'ha polsat per fer la gràfica ), ); }, ); }).toList(),//necessari ja que el widget column no treballa amb només un child, //treballa amb children, i en aquest cas només hi ha un. ), ), ), DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 75 119 120 121 122 123 124 125 126 127 128 129 130 131 floatingActionButton: FloatingActionButton(//es defineix un botó que depen de la variable //_isDiscovering child: Icon(_isDiscovering ? Icons.stop : Icons.search),//si s'està buscant que aparegui //la icona de stop, sinó de search. If _isDiscovering = True, que es mostri stop, //i si es false que es mostri la lupa. onPressed: _isDiscovering ? null : _startScan,//quan es prem el botó i està en "false" la variable //s'executa la funció _startScan backgroundColor: _isDiscovering ? Colors.red : null,//si s'està buscant, el fons del botó //es vermell, mentre que si no, el fons es el predeterminat (blau) ), ); } } A5. Codi “BluetoothDeviceListItem.dart”. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import '../styles/Styles.dart'; //aquí és on crea l'espai i la estructura de cada un dels ítems de la llista class BluetoothDeviceListItem extends StatelessWidget { const BluetoothDeviceListItem( {Key? key, required this.device, required this.onTap}) : super(key: key); //es defineix el widget, que té dues propietats indispensables. Una és device (que porta la informació //del dispositiu, i després una funció que s'executa quan es polsa algún element de la llista. final BluetoothDevice device;//variables de lectura final VoidCallback onTap; Widget _buildTitle(BuildContext context) { if (device.name != null) { //es comprova si el dispositiu té un nom que NO és "null" return Column(//si no és "null" es retorna el widget column amb certes característiques mainAxisAlignment: MainAxisAlignment.start, //per alinear verticalment crossAxisAlignment: CrossAxisAlignment.start, //per alinear horitzontalment children: <Widget>[ Text( device.name ?? '',//asigna a text // el nom del dispositiu, però si el nom és "null", es fica cadena buida: '' overflow: TextOverflow.ellipsis, //d'aquesta forma ens asegurem que sempre es proporciona un valor no "null" //encara que amb la condició "if" ja s'especifica que no pot ser Annexos 76 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 ) ], ); } else { return Text( device.address); //si no té nom, (és "null"), que es fiqui l'adressa } } @override Widget build(BuildContext context) { //utilitza el "_buildTitle" anterior per a obtenir el seu //widget i modificar-o afegint el botó return Container( padding: const EdgeInsets.all(8.0), //espai de 8 píxels en totes les direccions decoration: BoxDecoration( border: Border.all(color: Colors.grey),//decoració de la "caixa" que envolta cada fila borderRadius: BorderRadius.circular(8.0), ), child: ListTile(//per afegir el contingut del "container" title: _buildTitle(context),//s'obté el widget del títol anterior i es construeix trailing: ElevatedButton( //"trailing" serveix per especificar que es col·loca a la dreta del tot child: Text('CONNECT'), onPressed: onTap, //al polsar-se, que s'executi aquesta funció que està en: "FindDevicesScreen" ), ), ); } } A6. Codi “DeviceScreen.dart”. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import 'dart:async'; //permet fer ús del timer import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bluetooth_serial/flutter_bluetooth_serial.dart'; import 'package:syncfusion_flutter_charts/charts.dart';//per poder crear i mostrar gràfics class DeviceScreen extends StatefulWidget { const DeviceScreen({Key? key, required this.device}) : super(key: key); //device obtingut en la "page" "FindDevicesScreen" final BluetoothDevice device;//el dispositiu del qual ens hem connectat @override _DeviceScreenState createState() => _DeviceScreenState(); //es crea un estat per controlar l'estat de la finestra } class _DeviceScreenState extends State<DeviceScreen> { //es crea una extensió de l'estat de la pantalla DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 77 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 final List<ChartData> _chartData = [];//crea una llista on s'emmagatzemarà //les dades a mesura que es reben per bluetooth int _counterX = 0;//comptador pels valors X del gràfic BluetoothConnection? _connection;//per representar que s'ha establert connexió amb el dispositiu //variable de tipus “BluetoothConnection”, pot tenir valor negatiu per això el “?” StreamSubscription<String>? _dataSubscription; //variable per emmagatzemar la subscripció dispositiu // per a fluxe dades indica que el tipus de dades que es reben es de tipus String. Pot tenir valor negatiu @override //permet sobreescriure la funció initState, que ja existeix ja que //_DispDevicesScreenState es una extensió de State, i aquest State porta incorporat initState void initState() { super.initState(); _bondAndConnectToDevice();//només al iniciar-se el widget, es crida a aquestes dues funcions } @override void dispose() {//quan es finalitzi aquesta finestra s’executa: _dataSubscription?.cancel();//es cancel·la la subscripció _connection?.dispose();//és una instrucció proporcionada per la llibreria de flutterbluetoothserial, //la qual tanca la connexió Bluetooth i es lliveren tots els recursos utilitzats super.dispose(); } Future<void> _bondAndConnectToDevice() async {//es realitza la vinculació “bonding” necessària abans //de connectar-se al dispositiu. Acció possible gràcies a “flutter_bluetooth_serial”. Asíncrona String targetAddress = widget.device.address;//s'obté la direcció del dispositiu seleccionat //i es guarda en la variable List<BluetoothDevice> bondedDevices = await FlutterBluetoothSerial.instance.getBondedDevices(); //es demana la llista de dispositius prèviament vinculats i s’espera a que es completi la operació //per continuar.”FlutterBluetoothSerial” és una instrucció del paquet abans comentat. Es guarda a “bondedDevices” bool isBonded = bondedDevices.any((device) => device.address == targetAddress); //es comprova si el dispositiu ja està vinculat. Es compara direccions fent una iteració “any”. //retorna true si coincideix algún “device” de “bondedDevices” amb el device.adress actual if (!isBonded) { // si el dispositiu no està vinculat, s'intenta fer-ho await FlutterBluetoothSerial.instance.bondDeviceAtAddress(targetAddress); } //”bondDeviceAdress” també és del paquet “flutterBluetoothSerial” _connectToDevice();//si ja estava vinculat o es vincula, ens anem cap a la funció especificada. } Future<void> _connectToDevice() async {//en aquesta funció, s'estableix la connexió amb el dispositiu //i la gestió de les dades await BluetoothConnection.toAddress(widget.device.address).then((_connection) { //de la llibreria flutterBluetoothSerial. Estableix connexió amb el dispositiu //fent ús de la seva direcció. Es retorna un objecte de tipus BluetoothConnection //”_connection” representa si la connexió s’ha establert o no _connection.input?.listen((data) {//mitjançant el ".listen", es permet rebre dades del dispositiu //bluetooth al qual s'ha establert la connexió. Dades emmagatzemades en “data” Annexos 78 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 //el “?” vol dir que només el fluxe està actiu quan “_connection” no és “null” (negatiu) if (_counterX > 1000) { //simplement el que fa aquesta funció és reiniciar les dades que es mostren //quan "_counterX" supera el valor de 1000. S'ha escollit aquest valor ja que es un valor quasi exacte // a 1030, que és la amplitud en X del gràfic.Correspon a més o menys 5,5s.Arduino 153 m/s.Aquí 181,81 m/s. setState(() { _chartData.clear();//es borren tots els elements de la llista (del gràfic) _counterX = 0;//es reinicia el comptador en X }); } String str = String.fromCharCodes(data);//IMPORTANT; aquesta línea converteix l'objecte //"List<int>" que és el que es rep en una "string". Converteix bytes en caràcters. List<String> lines = str.split('\r\n');//cada cop que es rep \n i \n en la cadena que entra // doncs es considera que és un nou valor. A partir del "string" (“str”) anterior, genera //línies separades pel criteri comentat for (String line in lines) {//fa una iteració per cada línia creada anteriorment //i guarda el resultat en "line" print(lines);//aquí s'ha fet un print per visualitzar un problema que hi havia //comentar en el treball aquest problema int? value = int.tryParse(line); //intenta convertir cada "line" a un enter //i ho guarda en "value" if(value != null) { //si s'ha realitzat correctament la conversió a enter: if (value > 100) { //els valors més petits a 100 no es mostren (0.489 V), ja que hi han problemes a l'hora de rebre //els valors a trvés del Bluetooth, es generen valors molt baixos de forma //totalment aleatoria setState(() { _chartData.add(ChartData(_counterX, value)); //es modifica la lista "_charData" //el valor X és el comptador i el valor en Y és el "value" _counterX += 1; //s'incrementa en 1 el comptador en X }); } else { //per si el valor és <100 setState(() { _chartData.add(ChartData(_counterX, _chartData.last.value)); //afegeix en Y //el valor anterior _counterX += 1;//incrementar en comptador en X }); } } } }); }); } @override Widget build(BuildContext context) {//es crea una estructura return Scaffold(//instrucció típica per estructures appBar: AppBar(//encapçalament title: Text(widget.device.name ?? 'Unknown device'),//si es coneix el nom, que el text DISSENY I IMPLEMENTACIÓ D'UN PROTOTIP D'ELECTROCARDIÒGRAF AMB VISUALITZACIÓ DEL SENYAL EN TEMPS REAL. 79 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 //sigui el nom, sino que el text sigui "Unknown device" ), body: SingleChildScrollView(//per a poder navegar verticalment quan el contingut excedeix child: Column( children: <Widget>[ Container( height: 300,//es crea un contenedor de 300 pixels d'altura child: SfCartesianChart(//de la biblioteca "syncfusion_flutter_charts"es crea un //gràfic cartesià primaryXAxis: NumericAxis(//es defineix com a eix numèric title: AxisTitle( text: 'Time', ), minimum: 0, // Valor mínim per l'eix X maximum: 1030, // Valor màxim per l'eix X interval: 50),//separacions en la gràfica primaryYAxis: NumericAxis( title: AxisTitle( text: 'Volts [V]', ), minimum: 0, // Valor mínim per l'eix Y maximum: 1100, // Valor màxim per l'eix Y interval: 50),//separacions en la gràfica series: <ChartSeries>[//es defineix el gràfic LineSeries<ChartData, int>( //s'especifica que s'utilitza un gràfic //de tipus lineal dataSource: _chartData,//s'indica la font de les dades xValueMapper: (ChartData data, _) => data.valueX,//s'indica el valor de la X yValueMapper: (ChartData data, _) => data.value,//s'indica el valor de la y ), ]), ), ], ), ), ); } } class ChartData { final int valueX; final int value; ChartData(this.valueX, this.value);//s'emmagatzema els valors de x, y en //"ChartData" }