Meta
El objetivo de este miniproyecto/tutorial es crear un monitor de frecuencia cardíaca y una pantalla de ECG con desplazamiento súper simple con componentes mínimos.
Requisitos:
Antecedentes rápidos
Los músculos del corazón crean señales eléctricas. Algunas de esas señales son detectables en la superficie de la piel.
Podemos captar esas señales utilizando electrodos de superficie. El problema es que estas no son las únicas señales eléctricas en la piel. Afortunadamente, la mayoría de las señales que queremos ver se limitan a alrededor de 1-40 Hz.
Proceso
Vamos a tomar nuestro cable de 1/4", que actuará como nuestro electrodo y lo introduciremos en nuestra piel cerca del corazón. Luego usaremos la interfaz de audio USB para amplificar y convertir la señal analógica a digital. Finalmente filtramos y mostramos en Python
.Pasos
Paso 1: Un cable de 1/4" tiene dos partes, la funda y la punta. Ambas partes deben hacer contacto con la piel; simplemente sostenga la funda con la mano y aplástela contra la lado izquierdo de su pecho/caja torácica superior (algunos cables pueden tener más canales, solo asegúrese de que todos tengan contacto para comenzar. Ajuste la ganancia en la interfaz de audio (yo subo el mío al máximo).
Paso 2: Ejecute el siguiente código. Asegúrate de verificar que la línea input_device_index apunte a tu interfaz de audio. Lo que estamos haciendo es tomar fragmentos del audio entrante, convertirlos al dominio de la frecuencia usando fft, establecer todas las frecuencias innecesarias en 0 y luego volver a convertirlos al dominio del tiempo. A continuación encontramos los picos para calcular la FC y luego graficamos de forma desplazable.
import numpy as np import pyaudio as pa import struct import matplotlib.pyplot as plt from scipy.signal import decimate, find_peaks CHUNK = 4410 #.1 second FORMAT = pa.paInt16 CHANNELS = 1 RATE = 44100 # in Hz fstep = RATE/CHUNK p = pa.PyAudio() values = [] dsf=44 #down sample factor rds=RATE/dsf #down sampled rate stream = p.open( format = FORMAT, channels = CHANNELS, rate = RATE, input_device_index=3, #adjust based on input input=True, frames_per_buffer=CHUNK ) #set up graph fig,ax = plt.subplots(1) x = np.arange(0,2*CHUNK,2) line, = ax.plot(x, np.random.rand(CHUNK)) ax.set_ylim(-100,100) ax.set_xlim(0,2500) text = ax.text(0.05, 0.95, str(0), transform=ax.transAxes, fontsize=14, verticalalignment='top') fig.show() def getFiltered(x,hp=1,lp=41): #this sets the unneeded freqs to 0 fft=np.fft.fft(x) hptrim=len(fft)/RATE*hp lptrim=len(fft)/RATE*lp fft[int(lptrim):-int(lptrim)]=0 fft[0:int(hptrim)]=0 return np.real(np.fft.ifft(fft)) def getHR(x): pdis = int(0.6 * rds) #minimum distance between peaks. stops rapid triggering. also caps max hr, so adjust peaks, _ = find_peaks(x, distance=pdis, height=0.1) intervals = np.diff(peaks)/rds # in seconds hr = 60 / intervals # in BPM return peaks,round(np.mean(hr),0) #peaks,avg hr while 1: data = stream.read(CHUNK) dataInt = struct.unpack(str(CHUNK) 'h', data) filtered=getFiltered(dataInt) #filter (working with full chunk) dsed=decimate(filtered, 44) #down sample (turns chunk into ds chunk) values=np.concatenate((values,dsed)) #puts the chunks into an array peaks,hr = getHR(values*-1) # gets the peaks and determins avg HR. text.set_text(str(hr)) line.set_xdata(np.arange(len(values))) line.set_ydata(values*-10) #the negative is bc it comes in upside down with my set up. the *10 is just for fun ax.set_xlim(max(0,len(values)-2500),len(values)) #keep the graph scrolling vlines = ax.vlines(peaks,ymin=-100,ymax=100,colors='red', linestyles='dashed') # pop some lines at the peaks fig.canvas.draw() fig.canvas.flush_events() vlines.remove() if len(values)>10000: #keeps the array managably sized, and graph scrolling pretty values=values[5000:] #5 seconds @ ~1000 sr.
Notas
Mantenga el cable quieto; es posible que deba esperar unos segundos después del movimiento para obtener una frecuencia cardíaca precisa. Lo comparé con mi reloj Garmin y constantemente arrojó valores similares.
Producción
Descargo de responsabilidad
Tenga en cuenta que técnicamente está haciendo que su cuerpo forme parte del circuito. El cable está conectado a la interfaz que está conectada a la computadora que está conectada a la toma de corriente de pared... Pruebe esto bajo su propia responsabilidad. No soy un experto, simplemente disfruto jugando con cosas y quería compartirlas.
Próximos pasos
Este método realmente no funciona muy bien para ver claramente todas las diferentes partes de una señal de ECG. El electrodo está muy rayado y le hice un filtrado mínimo.
Tampoco funciona bien para detectar señales más pequeñas como la EMG.
Desde aquí puedes profundizar en el lado del software y jugar con filtros adicionales, o crear un circuito real y usar electrodos reales. Una bolsa de electrodos para este tipo de cosas es bastante barata en Amazon (aviso, el adhesivo es molesto). Para un circuito, probé algunas configuraciones diferentes; lo que encontré más simple/funcionó mejor para mí fue un circuito amplificador de instrumentación simple que usa un amplificador operacional JFET (montado en una placa de pruebas). 3 electrodos, solo busque un diagrama para saber dónde colocarlos. Si usa la interfaz de audio para el ADC, el código aquí debería funcionar con la placa de pruebas de 3 electrodos configurada (es posible que tenga que ajustar la ganancia)
Por qué
La inspiración para este miniproyecto surgió mientras jugaba con un complemento de ecualizador en un DAW mientras sostenía un cable de guitarra.
Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.
Copyright© 2022 湘ICP备2022001581号-3