هدف
الهدف من هذا المشروع الصغير/البرنامج التعليمي هو إنشاء شاشة مراقبة للموارد البشرية وشاشة تخطيط القلب قابلة للتمرير باستخدام الحد الأدنى من المكونات.
متطلبات:
خلفية سريعة
تقوم عضلات القلب بإنشاء إشارات كهربائية. بعض هذه الإشارات يمكن اكتشافها على سطح الجلد.
يمكننا التقاط تلك الإشارات باستخدام الأقطاب الكهربائية السطحية. المشكلة هي أن هذه ليست الإشارات الكهربائية الوحيدة على الجلد. ولحسن الحظ، فإن معظم الإشارات التي نرغب في رؤيتها تقتصر على حوالي 1-40 هرتز.
عملية
سنأخذ كابلنا مقاس 1/4 بوصة، والذي سيكون بمثابة قطب كهربائي لدينا وندخله في بشرتنا بالقرب من القلب. ثم نستخدم واجهة الصوت USB لتضخيم الإشارة التناظرية وتحويلها إلى رقمية أخيرًا نقوم بالتصفية والعرض في لغة بايثون.
خطوات
الخطوة 1: يتكون الكابل مقاس 1/4 بوصة من جزأين، الغلاف والطرف. يحتاج كلا الجزأين إلى ملامسة بشرتك - فقط أمسك الغلاف بيدك واهرسه على الجانب الأيسر من صدرك/القفص الصدري العلوي (قد تحتوي بعض الكابلات على قنوات أكثر، فقط تأكد من اتصالها جميعًا للبدء).
قم بتشغيل الكود أدناه. تأكد من أن سطر input_device_index يشير إلى واجهة الصوت الخاصة بك. ما نقوم به هو أخذ أجزاء من الصوت الوارد، والتحويل إلى مجال التردد باستخدام fft، وضبط جميع الترددات غير الضرورية على 0، ثم التحويل مرة أخرى إلى المجال الزمني. بعد ذلك نجد القمم لحساب الموارد البشرية ثم رسم بياني بطريقة التمرير.
استيراد numpy كـ np
استيراد pyaudio كـ pa
هيكل الاستيراد
استيراد matplotlib.pyplot كـ plt
من scipy.signal استيراد عشري، find_peaks
القطعة = 4410 #.1 ثانية
التنسيق = pa.paInt16
القنوات = 1
المعدل = 44100 # بالهرتز
fstep = معدل/قطعة
ع = pa.PyAudio()
القيم = []
dsf=44 #عامل العينة السفلي
rds=RATE/dsf #down معدل العينات
تيار = ص.فتح (
تنسيق = تنسيق،
القنوات = القنوات،
معدل = معدل،
input_device_index=3، #ضبط بناءً على الإدخال
الإدخال = صحيح،
frames_per_buffer=CHUNK
)
# إعداد الرسم البياني
الشكل، الفأس = plt.subplots(1)
س = np.arange(0,2*CHUNK,2)
الخط، = 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), تحويل=ax.transAxes, حجم الخط=14,
المحاذاة العمودية = "الأعلى")
الشكل.إظهار()
def getFiltered(x,hp=1,lp=41): #this يضبط التكرارات غير الضرورية على 0
ففت=np.fft.fft(x)
hptrim=len(fft)/RATE*hp
lptrim=len(fft)/RATE*lp
fft[int(lptrim):-int(lptrim)]=0
ft[0:int(hptrim)]=0
إرجاع np.real(np.fft.ifft(fft))
مواطن getHR(x):
pdis = int(0.6 * rds) #المسافة الدنيا بين القمم. توقف عن التحفيز السريع. أيضًا الحد الأقصى للساعة، لذا اضبطه
القمم، _ = find_peaks(x، المسافة = pdis، الارتفاع = 0.1)
الفواصل الزمنية = np.diff(القمم)/rds # بالثواني
ساعة = 60 / فواصل زمنية # في BPM
قمم العودة، round(np.mean(hr),0) #peaks,avg hr
بينما 1:
البيانات = تيار.قراءة (CHUNK)
dataInt = struct.unpack(str(CHUNK) 'h'، بيانات)
filtered=getFiltered(dataInt) #filter (العمل مع القطعة الكاملة)
dsed=decimate(filtered, 44) عينة #down (تحويل القطعة إلى قطعة ds)
value=np.concatenate((values,dsed)) # يضع القطع في مصفوفة
Peaks,hr = getHR(values*-1) # يحصل على القمم ويحدد متوسط HR.
text.set_text(str(hr))
line.set_xdata(np.arange(len(values)))
line.set_ydata(values*-10) #السلبية هي أنها تأتي مقلوبة مع الإعداد الخاص بي. *10 للمتعة فقط
ax.set_xlim(max(0,len(values)-2500),len(values)) # استمر في تمرير الرسم البياني
vlines = ax.vlines(peaks,ymin=-100,ymax=100,colors='red', linestyles='dashed') # انبثاق بعض الخطوط عند القمم
شكل.قماش.رسم()
الشكل.canvas.flush_events()
vlines.remove()
إذا len(values)>10000: #يحافظ على حجم المصفوفة بشكل يمكن التحكم فيه، ويتم تمرير الرسم البياني بشكل جميل
value=values[5000:] #5 ثواني @ ~1000 ريال.
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 الخاصة بي، وكانت تظهر دائمًا قيمًا مماثلة.
ضع في اعتبارك أنك من الناحية الفنية تجعل جسمك
جزءًا من الدائرة. يتم توصيل الكابل بالواجهة المتصلة بالكمبيوتر والتي متصلة بمأخذ الطاقة بالحائط... جرب هذا على مسؤوليتك الخاصة. أنا لست خبيرًا، أنا فقط أستمتع باللعب بالأشياء، وأردت مشاركتها.
لا تعمل هذه الطريقة بشكل جيد جدًا لرؤية جميع الأجزاء المختلفة لإشارة تخطيط القلب بشكل واضح. القطب الكهربائي مخدوش للغاية وقمت بالحد الأدنى من التصفية.
كما أنه لا يعمل بشكل جيد في اكتشاف الإشارات الأصغر مثل EMG.
من هنا يمكنك التعمق أكثر في جانب البرنامج والتلاعب بمرشحات إضافية، أو إنشاء دائرة فعلية واستخدام أقطاب كهربائية حقيقية. تعتبر حقيبة الأقطاب الكهربائية لهذا النوع من الأشياء رخيصة جدًا على أمازون (انتبه، المادة اللاصقة مزعجة). بالنسبة للدائرة، جربت بعض التكوينات المختلفة - ما وجدته أبسط/أفضل بالنسبة لي هو دائرة مكبر صوت بسيطة للأجهزة باستخدام JFET opamp (يتم وضعها معًا على لوحة التجارب). 3 أقطاب كهربائية، ما عليك سوى البحث عن رسم تخطيطي لمعرفة مكان وضعها. إذا كنت تستخدم واجهة الصوت لـ ADC، فيجب أن يعمل الكود هنا مع إعداد لوحة التجارب ثلاثية الأقطاب الكهربائية (قد يلزم ضبط الكسب)
لماذا
جاء الإلهام لهذا المشروع الصغير أثناء اللعب باستخدام مكون EQ الإضافي في DAW أثناء الإمساك بكابل الجيتار.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3