目标
这个迷你项目/教程的目标是用最少的组件制作一个超级简单的心率监视器和滚动心电图显示。
要求:
快速背景
心脏的肌肉产生电信号。其中一些信号可以在皮肤表面检测到。
我们可以使用表面电极拾取这些信号。问题是,这些并不是皮肤上唯一的电信号。值得庆幸的是,我们想要看到的大多数信号都限制在 1-40Hz 左右。
过程
我们将使用 1/4" 电缆作为电极,将其插入心脏附近的皮肤。然后我们使用 USB 音频接口放大模拟信号并将其转换为数字信号最后我们用python进行过滤和显示。
步骤
第 1 步: 1/4" 电缆有两个部分:套管和尖端。这两个部分都需要与您的皮肤接触 - 只需用手握住套管并将其压在胸部/上肋骨的左侧(某些电缆可能有更多通道,只需确保它们都可以接触即可启动)。调整音频接口的增益(我将我的一直调高)。
第 2 步: 运行以下代码。 确保检查 input_device_index 行是否指向您的音频接口。我们正在做的是获取传入音频的块,使用 fft 转换到频域,将所有不必要的频率设置为 0,然后转换回时域。接下来,我们找到峰值来计算 HR,然后以滚动的方式绘制图表。
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.
笔记
保持电缆不动 - 您可能需要在运动后等待几秒钟才能获得准确的心率。我对照我的 Garmin 手表检查了它,它始终返回相似的值。
输出
免责声明
请记住,从技术上讲,您正在使
您的身体成为电路的一部分。电缆连接到连接到计算机的接口,该接口连接到计算机连接到墙壁电源插座...尝试此操作需要您自担风险。我不是专家 - 我只是喜欢玩弄东西,并想分享。
后续步骤
这种方法对于清楚地看到心电图信号的所有不同部分来说并不能很好地发挥作用。电极非常磨损,我只做了最低限度的过滤。
从这里,您可以在软件方面进行更深入的挖掘并使用其他滤波器,或者创建实际电路并使用真实电极。用于此类物品的一袋电极在亚马逊上非常便宜(注意,粘合剂很烦人)。对于电路,我尝试了几种不同的配置 - 我发现最简单/最适合我的是使用 JFET 运算放大器的简单仪表放大器电路(放在面包板上)。 3个电极,只需查一下图表即可知道放置位置。如果您使用 ADC 的音频接口,此处的代码应与设置的 3 电极面包板配合使用(可能需要调整增益)
为什么
这个迷你项目的灵感来自于拿着吉他线在 DAW 中使用 EQ 插件时的感受。
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3