」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 簡單DIY心率監測器+心電圖顯示器

簡單DIY心率監測器+心電圖顯示器

發佈於2024-11-09
瀏覽:391

目標
這個迷你專案/教學的目標是用最少的組件製作一個超級簡單的心率監視器和滾動心電圖顯示。

要求:

  • Python
  • 音訊介面
  • 1/4吋線/吉他線/樂器線(只需透過音訊介面連接電腦即可)

快速背景

心臟的肌肉產生電訊號。其中一些訊號可以在皮膚表面檢測到。

我們可以使用表面電極來擷取這些訊號。問題是,這些並不是皮膚上唯一的電訊號。值得慶幸的是,我們想要看到的大多數訊號都限制在 1-40Hz 左右。

過程

我們將使用 1/4" 電纜作為電極,將其插入心臟附近的皮膚。然後我們使用 USB 音訊介面放大類比訊號並將其轉換為數位訊號最後我們用python進行過濾和顯示。

步驟

第1 步: 1/4" 電纜有兩個部分:套管和尖端。這兩個部分都需要與您的皮膚接觸- 只需用手握住套管並將其壓在胸部/上肋骨的左側(某些電纜可能有更多通道,只需確保它們都可以接觸即可啟動)。

Simple DIY HR Monitor ECG Display

第 2 步:

執行下列程式碼。 確保檢查 input_device_index 行是否指向您的音訊介面。我們正在做的是獲取傳入音訊的區塊,使用 fft 轉換到頻域,將所有不必要的頻率設為 0,然後轉換回時域。接下來,我們找到峰值來計算 HR,然後以滾動的方式繪製圖表。
將 numpy 導入為 np 將 pyaudio 導入為 pa 導入結構體 將 matplotlib.pyplot 導入為 plt 從 scipy.signal 導入抽取,find_peaks 區塊 = 4410 #.1 秒 格式 = pa.paInt16 頻道 = 1 速率 = 44100 # 以赫茲為單位 fstep = 速率/區塊 p = pa.PyAudio() 值 = [] dsf=44 #下取樣因子 rds=RATE/dsf #下取樣率 流 = p.open( 格式=格式, 頻道=頻道, 比率 = 比率, input_device_index=3, #根據輸入調整 輸入=真, frames_per_buffer=區塊 ) #設定圖表 圖,ax = plt.子圖(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) 文字 = ax.text(0.05, 0.95, str(0), 變換=ax.transAxes, 字體大小=14, 垂直對齊='頂部') 圖.show() def getFiltered(x,hp=1,lp=41): #這將不需要的頻率設為0 fft=np.fft.fft(x) hptrim=len(fft)/速率*hp lptrim=len(fft)/速率*lp fft[int(lptrim):-int(lptrim)]=0 fft[0:int(hptrim)]=0 返回 np.real(np.fft.ifft(fft)) def getHR(x): pdis = int(0.6 * rds) #峰之間的最小距離。停止快速觸發。也限制了最大小時,所以調整 峰值, _ = find_peaks(x, 距離=pdis, 高度=0.1) 間隔 = np.diff(peaks)/rds # 以秒為單位 小時 = 60 / BPM 中的間隔# 返回峰值,round(np.mean(hr),0) #peaks,avg hr 而1: 資料 = 流.read(CHUNK) dataInt = struct.unpack(str(CHUNK) 'h', data) Filtered=getFiltered(dataInt) #filter(使用完整區塊) dsed=decimate(filtered, 44) #down 樣本(將 chunk 變成 ds chunk) value=np.concatenate((values,dsed)) #將區塊放入陣列中 Peaks,hr = getHR(values*-1) # 取得峰值並確定平均 HR。 文字.set_text(str(小時)) line.set_xdata(np.arange(len(值))) line.set_ydata(values*-10) #缺點是 bc 它與我的設定顛倒了。 *10 只是為了好玩 ax.set_xlim(max(0,len(values)-2500),len(values)) #保持圖表滾動 vlines = ax.vlines(peaks,ymin=-100,ymax=100,colors='red', linestyles='dashed') # 在峰值處彈出一些線條 圖.canvas.draw() Fig.canvas.flush_events() vlines.remove() if len(values)>10000: #保持數組大小可控,並且圖形滾動漂亮 值=值[5000:] #5 秒 @ ~1000 sr。

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 手錶檢查了它,它始終返回相似的值。

輸出


Simple DIY HR Monitor ECG Display

免責聲明

請記住,從技術上講,您正在使您的身體
成為電路的一部分。電纜連接到連接到電腦的接口,該接口連接到電腦連接到牆壁電源插座...嘗試此操作需要您自擔風險。我不是專家 - 我只是喜歡玩弄東西,並想分享。

後續步驟

這種方法對於清楚地看到心電圖訊號的所有不同部分來說並不能很好地發揮作用。電極非常磨損,我只做了最低限度的過濾。
它在檢測肌電圖等較小訊號方面也表現不佳。

從這裡,您可以在軟體方面進行更深入的挖掘並使用其他濾波器,或建立實際電路並使用真實電極。用於此類物品的一袋電極在亞馬遜上非常便宜(注意,黏合劑很煩人)。對於電路,我嘗試了幾種不同的配置 - 我發現最簡單/最適合我的是使用 JFET 運算放大器的簡單儀表放大器電路(放在麵包板上)。 3個電極,只需查一下圖表即可知道放置位置。如果您使用 ADC 的音訊接口,此處的代碼應與設定的 3 電極麵包板配合使用(可能需要調整增益)

為什麼

這個迷你項目的靈感來自於拿著吉他線在 DAW 中使用 EQ 插件時的感受。

版本聲明 本文轉載於:https://dev.to/benwwq/simple-diy-hr-monitorecg-display-4ol5?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 為什麼 useState 在嚴格模式下渲染元件兩次?
    為什麼 useState 在嚴格模式下渲染元件兩次?
    理解useState中的雙重渲染在React中,useState鉤子通常用於管理元件狀態。但是,在某些條件下,您可能會注意到使用 useState 呈現的元件對於每次狀態更新都會呈現兩次。這種行為讓許多未啟用嚴格模式的開發人員感到困惑。為什麼會出現這種情況? 嚴格模式的作用與未啟用嚴格模式的假設相反...
    程式設計 發佈於2024-11-09
  • 混淆技術如何保護PHP智慧財產權?
    混淆技術如何保護PHP智慧財產權?
    混淆PHP 代碼以保護知識產權作為軟體開發人員,保護原始碼至關重要,尤其是在計劃出售您的作品時。混淆技術為增強 PHP 程式碼的機密性提供了一個有價值的解決方案。 混淆方法混淆涉及將 PHP 程式碼轉換為混亂版本,該版本保留功能但妨礙人類可讀性。有幾種工具和技術可以實現此目的:1。 PHP 加速器這...
    程式設計 發佈於2024-11-09
  • 如何使用 JavaScript 修改外部樣式表中定義的 CSS 值?
    如何使用 JavaScript 修改外部樣式表中定義的 CSS 值?
    使用 JavaScript 修改 CSS 值JavaScript 提供了一種設定內聯 CSS 值的簡單方法。然而,當修改非內聯樣式表中定義的 CSS 值時,此方法可能會帶來挑戰。 從樣式表中擷取 CSS 值要擷取非內聯樣式表中的 CSS 值非內聯,JavaScript 允許透過 document.s...
    程式設計 發佈於2024-11-09
  • 如何在 PHP 中計算日期之間的小時差?
    如何在 PHP 中計算日期之間的小時差?
    確定 PHP 中日期之間的小時差您希望計算兩個日期之間的小時差,其格式為 " Y-m-d H:i:s."要實現這一點PHP:要實現這一點PHP:$timestamp1 = strtotime($date1); $timestamp2 = strtotime($date2);時間戳...
    程式設計 發佈於2024-11-09
  • 反應受控/不受控組件
    反應受控/不受控組件
    在 React 中,處理表單輸入主要有兩種方法: 受控組件 不受控制的組件 受控組件提供更多控制和驗證,而不受控組件更簡單,對於間歇性值存取的基本形式有用。 受控組件 這些是表單輸入,其值由 React State 控制。每當輸入的值發生變化時,狀態變數就會更新,並且輸入的值是透過...
    程式設計 發佈於2024-11-09
  • 如何處理 Selenium 中的「過時元素引用」異常?
    如何處理 Selenium 中的「過時元素引用」異常?
    陳舊元素引用:揭示原因並尋找解決方案在Selenium 中,遇到“陳舊元素引用”異常可能會令人沮喪,因為它表明被引用的元素不再附加到頁面文件。當 DOM 發生重大變更(例如動態載入或頁面導覽)時,通常會發生此錯誤。 要解決此問題,確定觸發異常的確切程式碼行至關重要。在提供的程式碼中,導致錯誤的行似乎...
    程式設計 發佈於2024-11-09
  • 如何有效率地在嵌套的 JavaScript 物件中尋找特定物件?
    如何有效率地在嵌套的 JavaScript 物件中尋找特定物件?
    迭代嵌套的JavaScript 物件迭代嵌套的JavaScript 物件可能具有挑戰性,特別是當您需要基於屬性檢索特定對象時價值。讓我們考慮以下範例:var cars = { label: 'Autos', subs: [ { label: 'SUVs', s...
    程式設計 發佈於2024-11-09
  • 最簡單的狀態教程
    最簡單的狀態教程
    Zustand 是一個小型、快速且可擴展的 React 狀態管理庫,可作為 Redux 等更複雜解決方案的替代方案。 Zustand 獲得如此大關注的主要原因是與 Redux 相比,它的體積小且語法簡單。 了解 Zustand 設置 首先,如果您還沒有安裝 Zustand 和 Ty...
    程式設計 發佈於2024-11-09
  • MongoDB 伺服器:概述
    MongoDB 伺服器:概述
    MongoDB 是一种流行的 NoSQL 数据库,提供高性能、可扩展且灵活的数据存储解决方案。与使用表和行的传统关系数据库不同,MongoDB 使用灵活的、类似 JSON 的结构(称为 BSON(二进制 JSON))将数据存储在文档中。这使得 MongoDB 能够轻松处理复杂的数据类型和层次关系。...
    程式設計 發佈於2024-11-09
  • 如何在 MySQL DELETE 語句中使用 LIMIT 刪除一定範圍的行?
    如何在 MySQL DELETE 語句中使用 LIMIT 刪除一定範圍的行?
    更正帶有LIMIT 的MySQL DELETE 語句的語法嘗試使用帶有LIMIT 的DELETE 語句從MySQL時LIMIT 子句,如果語法不正確,您可能會遇到錯誤。此錯誤通常表示用於指定限制的語法有問題。 所提供的查詢中的問題是您無法在 DELETE 語句的 LIMIT 子句中指定偏移量。在 D...
    程式設計 發佈於2024-11-09
  • 如何使用 os.walk() 在 Python 中建立帶有深度指示器的結構化目錄清單?
    如何使用 os.walk() 在 Python 中建立帶有深度指示器的結構化目錄清單?
    在Python 中使用os.walk() 遞歸地導航目錄為了創建更結構化的目錄列表,開發人員嘗試修改他們的程式碼將目錄顯示為大寫標題,並用虛線指示深度和目錄下的檔案。然而,他們最初的方法產生了不完整的結果。 為了解決這個挑戰,我們可以利用 Python 的 os.sep 屬性來正確描述路徑元件。這是...
    程式設計 發佈於2024-11-09
  • Java 中的設計模式及其範例
    Java 中的設計模式及其範例
    Java 中的設計模式是什麼? 設計模式是軟體設計中常見問題的可重複使用解決方案。它們代表了可應用於軟體開發中各種情況的最佳實踐,特別是像 Java 這樣的物件導向程式設計。 設計模式的類型 創建模式: 處理物件創建機制。 結構模式: 關注類別與物件的組成方...
    程式設計 發佈於2024-11-09
  • NestJS 與 Encore.ts:為您的 TypeScript 微服務選擇正確的框架
    NestJS 與 Encore.ts:為您的 TypeScript 微服務選擇正確的框架
    Introduction When web applications grow larger, so does the complexity in developing and maintaining the system. A common way to solve this i...
    程式設計 發佈於2024-11-09
  • 如何在 Python 中重置生成器物件?
    如何在 Python 中重置生成器物件?
    在Python 中重置生成器物件:探索替代方案產生器提供了一種迭代值序列的有效方法,而無需在記憶中。然而,一旦生成器產生了所有值,它就會耗盡並且不能直接重複使用。這就提出瞭如何在 Python 中重置生成器物件的問題。 不幸的是,生成器沒有內建的重置方法。要重複使用生成器,您有多種選擇:再次運行生成...
    程式設計 發佈於2024-11-09
  • 如何有效率地檢索MySQL中最後插入的行?
    如何有效率地檢索MySQL中最後插入的行?
    檢索 MySQL 中最後插入的行:高效方法高效檢索 MySQL 中最後插入的行是資料庫程式設計中的常見任務。以下是實現此目的的兩種有效方法:1。時間戳列:理想的解決方案是建立一個 TIMESTAMP 列,在行插入時自動捕獲當前時間戳記。這提供了一種可靠且準確的方法來確定最近的記錄。 2。 ORDER...
    程式設計 發佈於2024-11-09

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3