C語言的也有,但是是繪圖不方便,就先拿Python寫了,我直接接了一個串口來解析的數據,第一部分是電路焊接。
板子的接口定義
這個就是串口的全套
在這里可以更改波特率
焊盤
這個板子上面焊接了一塊藍牙的穿透模塊:
左上的位置和下面的位置都是聯通的
TTL電平是傳輸級邏輯(Transistor-Transistor Logic)電路的信號電平。TTL電路使用雙極性晶體管實現邏輯功能,所以TTL電平也稱為雙極性邏輯電平。TTL電平有兩種,高電平(HIGH)和低電平(LOW):-
高電平:大于2.4V,通常是5V。這代表邏輯"1"。
低電平:小于0.8V,通常是0V。這代表邏輯"0"。
在TTL電路中,電平在2.4V到0.8V之間是不確定的,屬于無效區域。所以為了穩定和可靠地區分高低電平,都會選用遠離無效區域的電壓,通常是0V和5V。除了高低電平的幅值之外,TTL電平還有以下一些要點:
TTL電平的變化速率不能太快,通常小于1V/ns,否則會產生噪聲干擾TTL電
TTL輸入電平的閾值約為1.4V,超過該閾值會被識別為高電平,低于該閾值會被識別為低電平。
TTL輸出電平會受溫度的影響。通常會設計足夠大的邊緣區域(2.4V-0.8V)以適應溫度變化的影響。
TTL電平不夠穩定,輸出電平可能會發生assaults,導致接收端誤判電平。常用抑制assaults的方法是上拉或下拉電阻。
由于TTL電路功耗較大,輸出會有一定的驅動能力,一般可以驅動10個TTL輸入。
如果需要驅動更多輸入,可以用OpenCollector輸出來提高驅動能力。所以TTL電平是典型的雙極性邏輯電平,使用0V和5V代表低電平和高電平。
腦電采集+TGAM腦電模塊
我不記得上面的文章里面有沒有寫具體的解析協議,Python也是一樣的就是來解析串口的協議。
一開始的程序可以寫成這樣
1. EEGThread:這是讀取腦電波設備數據的線程。會通過串口讀取原始數據,解析并存儲在data, data2和data3列表中。這些數據分別代表腦電波值,放松值和專注值。
這個就是一個對現在來處理程序的前置情況的處理
2.ShowThread:這是顯示數據的線程。它會創建一個PyQtGrah窗口,包含兩個plot。第一個plot顯示腦電波值,第二個plot同時顯示放松值(綠色)和專注值(藍色)。該線程會不斷從data, data2和data3列表中讀取最新數據,更新plot的顯示。
3.程序入口:這里會啟動上述兩個線程,并調用QtGui.QApplication.instance().exec_()進入Qt事件循環。
4.checkEeg():這是一個幫助方法,用于檢查腦電波是否異常。通過檢測old_data和delta_data列表中超出閾值的數據數量,判斷是否異常。
5. serial和threading模塊用于串口通信和多線程。
6. pyqtgraph模塊用于完成數據的可視化顯示。
這個程序的工作流程如下:
1. EEGThread線程啟動,開始讀取串口數據。
2. 將解析后的腦電波,放松值和專注值數據 append 到 data, data2 和 data3 列表。
3. ShowThread線程啟動,創建PyQtGraph窗口和兩個plot。
4. ShowThread線程定期從上述3個列表讀取最新數據,更新plot的顯示。
5. 主程序進入Qt事件循環,ShowThread線程能定期更新顯示。
6. EEGThread線程持續讀取串口數據,不斷更新列表內容。這樣,通過兩個線程協同工作,實現了從腦電波設備獲取數據并實時顯示的功能。PyQtGraph提供了比較簡潔的API來完成數據可視化,相比matplotlib更適合這個實時顯示的場景。
這個方法checkList的參數是:
- list: 要檢查的列表
- num: 閾值它的功能是:通過遍歷list中的所有值,統計大于num的元素的數量,并返回這個數量。
舉例:
python a = [1, 3, 2, 5, 4] checkList(a, 3) # 返回2,因為a中有兩個值大于3 b = [1, 2, 1, 2] checkList(b, 3) # 返回0
基本的實現代碼如下:
python def checkList(self, list, num): count = 0 for i in list: if i > num: count += 1 return count
它定義了一個count變量,遍歷list中的每個元素i,如果i大于num,則count加1。遍歷完成后返回count的值,這個值就是大于num的元素數量。
這個方法的作用是提供一個列表值異常判斷的手段。通過設置一個閾值num,可以輕松統計列表中異常大的元素數量,從而判斷該列表的值是否異常。
在腦電波數據分析中,可以設置某個通道數據或差分數據的閾值,通過這個方法判斷腦電波數據是否出現異常的突增,這在腦電波監測中比較重要。
這個方法checkEeg用于判斷腦電波數據是否異常。
它的參數是:
- old_data: 原始腦電波數據的歷史記錄,包含多個數據列表
- delta_data: 差分腦電波數據的歷史記錄,
包含多個數據它的功能是:
通過checkList方法,統計old_data中的每個數據列表中大于200的值的數量。如果有3個數據列表的大于200的值的數量大于5,則old_num加1。
通過checkList方法,統計delta_data中的值大于50000的值的數量,賦值給delta_num。
如果old_num大于3,并且delta_num大于4,則返回True,說明腦電波數據異常。否則返回False,數據正常。
這實現了通過檢測原始數據和差分數據的異常值來判斷腦電波數據是否異常的目的。異常數據可能意味著受試者的腦電波出現突變,需要注意。示例:
python old_data = [[1, 2, 3, 210, 5], [3, 4, 5, 220, 6], [100, 2, 3, 4, 5]] delta_data = [1, 2, 3, 60000, 4, 5] checkEeg(old_data, delta_data) # 返回True,old_num=2,delta_num=1,所以數據異常
這個方法為腦電波數據的實時監測提供了重要的支持。通過定期調用這個方法,并檢查其返回值,可以實時判斷受試者的腦電波數據是否出現異常,有助于及時發現問題。
代碼中還可以繼續優化:
可以這樣的來設計腦電的數據
read這個函數是最重要的
那么就是可以變成重要的使用模式
這樣通過將數據讀取和解析的過程封裝在EEGData類中,外部程序只需要關注從該類獲取數據并進行顯示或其它處理,代碼會更清晰簡潔。這個封裝也使得EEGData類具有更高的復用性,如果有其它需要讀取和解析同樣串口數據的場景,可以直接復用這個類,而不是重新編寫讀取和解析的過程。
可視化的代碼再第一個版本的時候寫的就能顯示一個通道的
我想要更多的通道,那么可以這樣設計:
這樣通過參數就可以讓我彈性的獲得腦電可視化的數據
這個類EEGPlot的功能是:
1. 根據傳入的通道名稱ch_names,初始化一個圖形窗口和多個繪圖區域,每個區域對應顯示一路腦電波數據。
2. show_data方法用于刷新所有繪圖區的顯示,它接收所有的通道數據,并設置給相應的曲線來更新顯示。
3. start方法啟動一個定時器timer來周期調用show_data方法,實現數據的動態顯示。
4. 外部通過采集好的多通道數據調用show_data方法,EEGPlot內部會自動將數據映射到對應的繪圖區顯示。
這樣,通過這個封裝,可以很方便的支持任意數量的通道,并且內部自動處理數據如何映射到對應通道的顯示,外部只需要將整理好的最新數據傳入即可,簡化了多通道數據處理與顯示的難度。
在這段代碼中,t = serial.Serial(self.com, self.bps) 這一行打開了串口并初始化了Serial對象t。之后,代碼會進入一個死循環,持續的從串口讀取數據。主要的讀取流程如下:
1. 先讀取3個字節的數據b,用于檢測設備是否連上。如果b符合要求(b[0] == b[1] == 170 and b[2] == 4),則認為已經連接上設備。
成功
2. 然后再讀取5個字節的數據a。如果a符合要求(a[0] == 170 and a[1] == 170 and a[2] == 4 and a[3] == 128 and a[4] == 2),則繼續讀取。
3. 讀取8個字節的數據a,用于獲取實際的腦電波數據。
4. 從a中解析出高8位high和低8位low,構成16位的原始數據rawdata。rawdata會存儲在self.vaul列表中。
三和四的代碼太早了,還有一段串口重試。
1. 首先讀取8個字節的數據a。
2. 計算a中的第6和第7字節(數據部分)的校驗和sum。
3. 判斷a的前3個字節是否是170,170,32。如果是,設置y=1,否則y=0。
4. 判斷a的前5個字節是否是170,170,4,128,2。如果是,設置p=1,否則p=0。
5. 如果sum校驗失敗,并且y!=1和p!=1,則繼續讀取3個字節的數據b。
6. 從b中解析出c,d,e三個字節,并循環讀取直到c=170,d=170和e=4。
7.如果循環出的c,d,e符合要求,再讀取5個字節的數據g。如果g符合要求(g[0]=128和g[1]=2),則再次讀取8個字節的數據a。
8. 這樣重復3-7步,直到讀取一組校驗和sum正確的數據a為止。這個過程是數據讀取的重試機制。由于串口通信可能存在噪聲或幀錯誤,導致讀取的數據校驗失敗。這段代碼實現了這樣的重試機制:如果讀取的數據a校驗失敗,它不會直接丟棄這組數據。
而是繼續讀取,判斷下一組數據b是否為起始幀(170,170,4),如果是則繼續判斷g是否為頭兩字節(128,2),如果仍然符合則重新讀取一組完整的數據a。這樣通過在校驗失敗后繼續“撿漏”,增加了數據正確讀取的幾率。有效避免由于偶爾的通信錯誤導致丟失有效數據的問題。這在構建穩定性高的數據讀取機制時是很有用的方式。尤其是在通信環境較差的情況下,這段“重試”邏輯可以顯著提高數據的正確采集率。
上面的代碼不好看,讓我來重構一下:
這樣寫
這樣用
這個DataRetry類實現了數據讀取的重試邏輯,其功能是:
1. read方法讀取8字節數據a,并校驗數據校驗和。如果失敗,繼續讀取以判斷是否為起始幀和包頭。如果通過,則重新讀取8字節數據a。
2. 通過這種方式,內部實現了在校驗失敗后繼續讀取從而重新獲取完整數據的重試機制。
3. 使用簡單的try/except,外部程序可以輕松調用retry.read(),不需要關心內部的重試細節。讀取失敗由retry內部捕獲并重試,成功則返回數據。
4. 通過這個類,外部可以像讀取正常數據一樣簡單調用,但相比直接讀取,會顯著提高數據正確讀取的幾率,增強程序的健壯性。這個封裝使復雜的重試讀取邏輯和外部數據讀取接口解耦, outwardly具有簡單讀取的表象, inwardly卻具備重試的能力,體現了很好的封裝思想。
這里才是接上面的代碼繼續
5. 如果校驗和sum校驗失敗,會重新讀取數據,直到獲取一組正確的數據。
6. 如果讀取到的a數據第1,2字節為170,第3字節為32,則認為這是28字節的數據幀c。從c中可以解析出更多的信息,比如放松值和專注值,存儲在data2和data3列表。
7. 每10組數據,會對old_data和delta_data列表中的數據進行檢查,看是否異常。
8. 最后會清空self.vaul列表,準備讀取下一組數據。這樣,通過持續循環讀取串口數據,并解析存儲在不同列表中,實現了對腦電波原始數據,放松值和專注值的采集。這些數據會在其他線程ShowThread中讀取和顯示。
這里已經重構過了
這段代碼的功能是:
1. 讀取8字節的數據a,判斷a的前5字節是否是170, 170, 4, 128, 2。如果是,繼續解析a。
2. 從a中取出第5和第6字節(high和low)。
3. 計算high<<8 | low得到原始數據rawdata。如果rawdata大于32768,減去65536。
4.計算a的校驗和sum,如果等于a的第8字節,則將rawdata添加到列表self.vaul。
5. 如果校驗失敗,進入重試機制(省略)。如果讀取失敗,跳出。
6. 判斷a的前3字節是否是170, 170, 32。如果是,繼續讀取28字節的數據c。
7. 從c中解析出delta = c[7]<<16 | c[8]<<8 | c[9]。8. 顯示delta。
這個過程實現了:
1. 對讀取的8字節數據a進行校驗,如果通過則解析出原始腦電波采樣數據rawdata并添加到列表。
2. 在校驗失敗的情況下,進行重試讀取以盡量不丟失有效數據。
3. 如果a的數據標識為170,170,32,則繼續讀取28字節數據c,并從中解析出放松值或專注值delta的信息。
4. 顯示解析出的delta值。這個過程對應了從串口讀取一幀完整的腦電波數據,解析出原始采樣值rawdata,放松/專注值delta,并進行必要的校驗和重試機制來提高數據正確率。
external調用此過程,即可從串口解析和獲取腦電波的采樣數據、放松值與專注值,并判斷采集是否正常進行。通過定期調用,可實現對整個采集過程的監控。
這個類EEGData的功能是:
1. read方法讀取8字節和28字節的數據,并進行校驗與解析。
2. 如果通過校驗,將解析出的原始數據添加到data列表,放松/專注值添加到relax/focus列表。
3. 在校驗失敗時,進行數據重試讀取。讀取錯誤時,打印錯誤信息。
4. 提供data,relax和focus三個列表,分別存儲原始數據,放松值和專注值信息。5. get_sum方法用于計算校驗和。
ser = serial.Serial('COM11', 57600) # 打開串口 eeg = EEGData(ser) # 創建EEGData對象 while True: eeg.read() # 讀取并解析一組數據 # 使用eeg.data, eeg.relax和eeg.focus訪問解析出的數據 ...
使用代碼
1. EEGData類實現數據解析和采集,提供eeg.data, eeg.relax和eeg.focus三個列表存取解析后的數據。
2.ShowThread類實現一個顯示線程,從eeg對象中獲取最新數據并實時顯示。3. 主程序從串口read()讀取數據,并通過eeg對象解析。
4.show_thread啟動一個定時器周期調用show_data方法來顯示最新數據。
5. 這樣通過 ShowThread 的實時顯示和 EEGData的數據解析,實現了對整個腦電波采集過程的監視與反饋。
這個程序通過將數據采集、解析和顯示過程解耦到不同線程中的不同對象,使得整體邏輯清晰且專注。EEGData專注于數據解析,ShowThread專注于數據顯示,主程序只關注數據讀取本身。這體現了較好的邏輯劃分和職責分配。
審核編輯:劉清
-
晶體管
+關注
關注
77文章
9698瀏覽量
138322 -
C語言
+關注
關注
180文章
7605瀏覽量
136993 -
藍牙模塊
+關注
關注
30文章
575瀏覽量
55746 -
python
+關注
關注
56文章
4797瀏覽量
84745 -
TTL電平
+關注
關注
1文章
99瀏覽量
12003
原文標題:TGAM腦電模塊-實戰應用(良好封裝版)
文章出處:【微信號:TT1827652464,微信公眾號:云深之無跡】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論