上一次的實驗做到可以從pc端讀取到MindWave傳輸過來的腦電波原始數據了。
我是先定義一個結構體,該結構體對應保存所有能從硬件中取到的原始數據。
1 struct FD_DATA 2 { 3 int battery;//電量
4 int poor_signal;//連接質量
5 int attention;//專注度
6 int meditation;//冥想度
7 int raw;//原始數據
8 int delta;//δ波段
9 int theta;//θ腦波
10 int alpha1;//α腦波
11 int alpha2;//α腦波
12 int beta1;//β腦波
13 int beta2;//β腦波
14 int gamma1;//γ腦波
15 int gamma2;//γ腦波
16 int blink;//眨眼強度
17 };
讀取的函數為

1 struct FD_DATA FD_GetData(int conID) 2 { 3 struct FD_DATA data; 4 TG_ReadPackets(conID,1000);//一次讀取多個,否則在多線程中會因為某些數據包在緩存中而沒有讀取
5 data.battery=TG_GetValue(conID,TG_DATA_BATTERY); 6 data.poor_signal=TG_GetValue(conID,TG_DATA_POOR_SIGNAL); 7 data.attention=TG_GetValue(conID,TG_DATA_ATTENTION); 8 data.meditation=TG_GetValue(conID,TG_DATA_MEDITATION); 9 data.raw=TG_GetValue(conID,TG_DATA_RAW); 10 data.delta=TG_GetValue(conID,TG_DATA_DELTA); 11 data.theta=TG_GetValue(conID,TG_DATA_THETA); 12 data.alpha1=TG_GetValue(conID,TG_DATA_ALPHA1); 13 data.alpha2=TG_GetValue(conID,TG_DATA_ALPHA2); 14 data.beta1=TG_GetValue(conID,TG_DATA_BETA1); 15 data.beta2=TG_GetValue(conID,TG_DATA_BETA2); 16 data.gamma1=TG_GetValue(conID,TG_DATA_GAMMA1); 17 data.gamma2=TG_GetValue(conID,TG_DATA_GAMMA2); 18 data.blink=TG_GetValue(conID,TG_DATA_BLINK_STRENGTH); 19 if(data.poor_signal<=0) 20 { 21 ErrorNo=7; 22 data.poor_signal=0; 23 return data; 24 } 25 return data; 26 }
對於獲取數據的時間間隔,就有可能有不同的取法了,理論上是時時刻刻的取值的。但是,這樣就太占系統cpu了,那到底是多少時間取一次數據比較好呢,我試着1ms,10ms,100ms,500ms,1s,5s等不同的取數據,然后分析。在TG_BAUD_9600波特率情況下大概每500ms各個值就會有變化。
下面這個圖是我在100ms取一次數據獲得的
分別對應 attention meditation raw delta theta alpha1 alpha2 ... ... 可以可以看到所有有效的數據大概都是5次一次刷新,而其中的raw列就每次都刷新,這個raw波段,我們此次不會涉及到,只是說明每次都是有實際從硬件取到值的。
對於取多少比較好呢,我再進行測試的時候是1s取一次。(我覺得如果該算法用於實際,覺得這個取值的時間間隔可以再大一點。)這里我們就會有一個疑問了,每次從硬件中取到的數都不一樣,我們1s取一次的話,會不會丟失疲勞信息的有效數據呢。還有就是,按道理人腦是時時刻刻都再發射腦電波的。如果准確的說,1s有無數次采樣的話,會有無數種結果。到底為什么可以1s取一次,5s取一次呢?(Ps:這個時間間隔叫做采樣間隔)。
這個問題困擾我很長時間了,到最近才知道為什么。這個跟時域和頻域有關。還有什么傅立葉等等概念有關。
音樂——其實就是時/頻分析的一個極好例子,樂譜就是音樂在頻域的信號分布,而音樂就是將樂譜變換到時域之后的函數。從音樂到樂譜,是一次傅立葉或小波變換;從樂譜到音樂,就是一次傅立葉或小波逆變換。
關於這方面的知識我也似懂非懂的。我也不好解釋。反正就是最后對結果的影響不會很大,基本沒有影響。還有一點,那個腦電波耳機內部其實還是有做了一些處理的。具體的處理也是上面提到的各種很復雜的級數變換吧。
(^-^)?有點跑題了,接下來就是對取到的數據進行繪圖分析。為了看圖的方便,我這里只畫出attention和meditation的曲線,其他的類似。
我們截取其中的一段,可以看到,這些線波動很大,基本看不到有效的關系。
我這里采用兩種辦法進行預處理。用兩種辦法是為了反正在進行預處理的時候把有效的信息給處理掉了。所以要兩種辦法,然后這兩種辦法再進行一個相關性的假設檢驗。
1.第一種辦法是使用常用的辦法,就是采用滑動窗口。原理就是這個點的取值是通過計算左右的值的平均值。然后來確定這個值的。這樣就能保證是相對穩定的顯示了。
2.第二種辦法是采用自己叫做補償算法的。原理就是下一個點的值由上一個點來確定,下一個點取當前該點的值減去上一次的值的六十分之一再加上前一個點的值。(思路是這樣就能確保每次的增加或減少都是在可控的返回內,每次只是對前一個值的修修補補,不會有大的變化,這一點在接下來的圖中可以看出)。還有就是為什么是六十分之一其實百分之一,千分之一。數量級越小,表示受時間影響越大。不同環境該數值應該不同。
第二種辦法作用是檢驗attention和meditation在滑動窗口和補償算法中是否有顯著性相關,我們采用 基於成對數據的假設檢驗(t檢驗),來確定滑動窗口這個算法對數據的預處理的有效的,並不會破壞數據的有效信息。如果有顯著性相關的話就說明第一種辦法是可行的,那么,以后的處理就可以這是一種方法的預處理就可以了。
得到的是這樣的效果,分別是attention兩條曲線,meditation兩條曲線。這樣看就比較正常了,不像上面那樣沒有規律。我們這樣一眼望過去就可以知道兩種辦法取得的曲線是有點相關性的。作為一個專業的人來說,僅僅靠目測法是不行的。我們要怎樣解決呢?這里就要用到t檢驗了。這個是概率論與數理統計方面的。這個課是大二學的,具體的都忘了,當時也沒有怎么認真的學。現在看到這個問題就后悔當初沒有認真聽課了。(這里插一句,不能不想起當年大一的時候一個ACM的師兄說的一句話“你們是不是覺得大學的高數學了沒有用,那是你們還沒有到用到它的水平。”當時的理解是這是一個學霸師兄赤果果的嘲諷。現在想想也是有道理的。那個線性代數我是學那個矩陣快速冪算法的時候有用到,而這里的t檢驗是第一次實際例子中用到數理統計的。而前面提到的傅立葉是在高數中有提到的。如果時間可以倒流,回到那個時候,你還會不會認真的對待這些數學。我肯定的回答,應該還是不會。)
d’是樣本均值 Sd是樣本方差 n是樣本個數 α是置信區間 具體其他的就自己看書了。
還是給出代碼比較好理解吧
1 //基於成對數據的假使檢驗
2 double FD_t_check_pair(double * x,double * y,int size) 3 { 4 double * d; 5 double avg=0.0;//用於計算平均數
6 double sd=0.0;//用於保存方差
7 int i,j; 8 d=(double *)malloc(size*sizeof(double)); 9 for(i=0;i<size;i++) 10 { 11 d[i]=x[i]-y[i]; 12 avg=avg+d[i]; 13 } 14 avg=avg/size; 15 sd=0.0; 16 for(i=0;i<size;i++) 17 { 18 sd=sd+((avg-d[i])*(avg-d[i])); 19 } 20 sd=sd/(size-1); 21 printf("sd=%lf\n",sd); 22 double t; 23 t=fabs(avg/(sd/sqrt(size))); 24 free(d); 25 return t; 26 }
我得出的結論是在置信區間a=0.025 n=500 是attention和meditation對應的t值都是小於2.4的,說明觀察值|t| 不落在拒絕域內,故接受H假使,認為使用兩種預處理得到的結果無顯著差異。
好了,這一節就到這里了,有什么錯誤歡迎指出。下一節將講述 αβθ之間的關系,對人體的疲勞狀態是否有明顯的相關性。這一步將通過這些關系與硬件提供的attention值和meditation值進行相關性檢驗,來確定硬件給出的值是否有效,還有通過對人的具體實驗進行分析。總體代碼現在比較亂,就先不給出了,等以后有機會整理完再發吧。
參考資料:
概率論與數理統計及其應用 (高等教育出版社) (盛 驟 謝式千)
還有一個音樂的例子,網上都是寫轉載,但沒有給出出處,我就不好寫了。
本文鏈接:http://www.cnblogs.com/wunaozai/p/3766779.html