免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
最近暴火的電子血氧儀是什么原理?它真的測得準(zhǔn)嗎?

最近,隨著新冠病毒在國內(nèi)肆虐,繼口罩、抗原、藥品之后,血氧儀的價格也開始水漲船高。從1個多月前的100多元,暴漲到300多。

那么,這類家用的電子血氧儀是如何工作的呢?測量數(shù)據(jù)到底準(zhǔn)不準(zhǔn)?今天帶大家來分析一下。

1)血氧儀工作原理

血氧儀是一種監(jiān)測脈搏、血氧飽和度等指標(biāo)的醫(yī)療器械,常見的家用型血氧儀,主要有指夾式、腕表式等形式。

一般大家最關(guān)注的是血氧飽和度(oxygen saturation簡寫為SpO2),它是指在全部血容量中被結(jié)合O2容量占全部可結(jié)合的O2容量的百分比,是人體攜帶氧氣能力的重要參考值。人體正常的SpO2應(yīng)該不小于95%,長期低于93%時需要就醫(yī)。

SpO2 一般由以下公式計算:

其中CHbO2是氧合血紅蛋白濃度,CHb是還原血紅蛋白濃度。

一方面,這兩種血紅蛋白對不同波長的光有不同的吸收度;另一方面,當(dāng)動脈跳動時,動脈中的血液量會發(fā)生變化,可以區(qū)分出皮膚、肌肉、靜脈血等對光的吸收影響(這些組織對光的吸收可以認(rèn)為固定不變)。因此,利用兩種不同波長的光,經(jīng)透射或反射后,采集數(shù)據(jù)綜合處理,就能計算出血氧飽和度。

現(xiàn)在市面上最常見的,都是光電式的血氧儀,如下圖所示,有透射式和反射式兩種實現(xiàn)方法。

常見的指夾式血氧儀就是透射式,智能手環(huán)或手表就是反射式,原理是差不多的。

而LED光源的選擇,與血紅蛋白對不同光波長的吸收率有關(guān),下圖是兩種血紅蛋白對不同波長的光的消光系數(shù)圖:

可以看到,兩種血紅蛋白對波長為660nm左右光的吸收差別最大,而對波長為800nm左右光的吸收基本相等。理論上來說,使用660nm和800nm波長的光作為光源是最合適的,但是,由于在800nm左右時,二者的消光系數(shù)斜率相差較大,光波長偏差一點(diǎn)就會引起較大的吸收率變化,這對LED的制造工藝要求太高,所以,工程實現(xiàn)時,一般不用800nm波長的LED,而選擇波長為860nm~920nm的LED作為另一個光源,這個區(qū)間的消光系數(shù)斜率基本一樣,而且變化平緩。

好了,到這里,硬件部分的實現(xiàn)我們已經(jīng)了解了大概。核心就是要使用兩個LED作為光源,一個660nm波長的紅外光,一個900nm左右波長的紅光,兩束光分別通過透射(或反射)皮膚后,到達(dá)光電接收管,再采集光電接收管的值。

那么采集到兩個光源的值后,應(yīng)該如何處理呢?這里由于有比較多的公式推導(dǎo),我們直接略過,給出下面的公式:(出自Maxim公司的應(yīng)用文檔,相關(guān)文檔都能在文末關(guān)注公眾號找到網(wǎng)盤下載地址)

這里的實現(xiàn)需要三步:

首先,我們采集的兩個LED光源的值,需要分離出直流分量和交流分量,也就是:紅光的交流分量ACred、紅光的直流分量DCred、紅外光的交流分量ACired、紅外光的直流分量DCired;

其次,用采集到的四個值,計算出R;

最后,用R計算SpO2,這個計算公式中a、b、c是三個需要校準(zhǔn)的參數(shù)。需要大量的試驗數(shù)據(jù)去擬合出來。

2)血氧儀的制作

有了以上的理論基礎(chǔ),我們可以自己動手DIY一個血氧儀。

Maxim公司有一款集成芯片,可以實現(xiàn)大部分的硬件功能,就是MAX30100、MAX30102系列芯片。MAX30100已停產(chǎn),新設(shè)計中不推薦使用,MAX30102是新一代產(chǎn)品。

目前價格還沒有太離譜:

MAX30102集成了一個660nm紅光LED、880nm紅外光LED、光電檢測器,以及帶環(huán)境光抑制的低噪聲電子電路。芯片內(nèi)部含18bit ADC采集電路。對外是I2C接口?;旧蠁涡酒湍軐崿F(xiàn)光源信號的采集。

要注意,MAX30102的輸出值,只是兩個LED光源的采集值。后續(xù)還需要軟件去實現(xiàn)交流、直流分離,R的求解、SpO2的求解。順帶也可以求解出脈搏數(shù)據(jù)。

使用max30102很簡單,用I2C接口訪問,初始化代碼如下:

max30102_Bus_Write(REG_INTR_ENABLE_1,0xc0); // INTR settingmax30102_Bus_Write(REG_INTR_ENABLE_2,0x00);max30102_Bus_Write(REG_FIFO_WR_PTR,0x00); //FIFO_WR_PTR[4:0]max30102_Bus_Write(REG_OVF_COUNTER,0x00); //OVF_COUNTER[4:0]max30102_Bus_Write(REG_FIFO_RD_PTR,0x00); //FIFO_RD_PTR[4:0]max30102_Bus_Write(REG_FIFO_CONFIG,0x0f); //sample avg = 1, fifo rollover=false, fifo almost full = 17max30102_Bus_Write(REG_MODE_CONFIG,0x03); //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LEDmax30102_Bus_Write(REG_SPO2_CONFIG,0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS) max30102_Bus_Write(REG_LED1_PA,0x24); //Choose value for ~ 7mA for LED1max30102_Bus_Write(REG_LED2_PA,0x24); // Choose value for ~ 7mA for LED2max30102_Bus_Write(REG_PILOT_PA,0x7f); // Choose value for ~ 25mA for Pilot LED

主函數(shù)中循環(huán)調(diào)用fifo讀取函數(shù),用于獲取LED光源的采集值:

void maxim_max30102_read_fifo(uint32_t *pun_red_led, uint32_t *pun_ir_led){ uint32_t un_temp; unsigned char uch_temp; char ach_i2c_data[6]; *pun_red_led=0; *pun_ir_led=0;
//read and clear status register maxim_max30102_read_reg(REG_INTR_STATUS_1, &uch_temp); maxim_max30102_read_reg(REG_INTR_STATUS_2, &uch_temp);
IIC_ReadBytes(I2C_WRITE_ADDR,REG_FIFO_DATA,(u8 *)ach_i2c_data,6);
un_temp=(unsigned char) ach_i2c_data[0]; un_temp<<=16; *pun_red_led+=un_temp; un_temp=(unsigned char) ach_i2c_data[1]; un_temp<<=8; *pun_red_led+=un_temp; un_temp=(unsigned char) ach_i2c_data[2]; *pun_red_led+=un_temp;
un_temp=(unsigned char) ach_i2c_data[3]; un_temp<<=16; *pun_ir_led+=un_temp; un_temp=(unsigned char) ach_i2c_data[4]; un_temp<<=8; *pun_ir_led+=un_temp; un_temp=(unsigned char) ach_i2c_data[5]; *pun_ir_led+=un_temp; *pun_red_led&=0x03FFFF; //Mask MSB [23:18] *pun_ir_led&=0x03FFFF; //Mask MSB [23:18]}

采集值最好經(jīng)過濾波,以減少噪聲的干擾。

之后,再分離出交流、直流分量,求出R和SpO2即可,核心是這個函數(shù):

void maxim_heart_rate_and_oxygen_saturation(uint32_t *pun_ir_buffer, int32_t n_ir_buffer_length, uint32_t *pun_red_buffer, int32_t *pn_spo2, int8_t *pch_spo2_valid, int32_t *pn_heart_rate, int8_t *pch_hr_valid){ uint32_t un_ir_mean ,un_only_once ; int32_t k ,n_i_ratio_count; int32_t i, s, m, n_exact_ir_valley_locs_count ,n_middle_idx; int32_t n_th1, n_npks,n_c_min; int32_t an_ir_valley_locs[15] ; int32_t an_exact_ir_valley_locs[15] ; int32_t an_dx_peak_locs[15] ; int32_t n_peak_interval_sum; int32_t n_y_ac, n_x_ac; int32_t n_spo2_calc; int32_t n_y_dc_max, n_x_dc_max; int32_t n_y_dc_max_idx, n_x_dc_max_idx; int32_t an_ratio[5],n_ratio_average; int32_t n_nume, n_denom ; // remove DC of ir signal un_ir_mean =0; for (k=0 ; k<n_ir_buffer_length ; k++ ) un_ir_mean += pun_ir_buffer[k] ; un_ir_mean =un_ir_mean/n_ir_buffer_length ; for (k=0 ; k<n_ir_buffer_length ; k++ ) an_x[k] = pun_ir_buffer[k] - un_ir_mean ; // 4 pt Moving Average for(k=0; k< BUFFER_SIZE-MA4_SIZE; k++){ n_denom= ( an_x[k]+an_x[k+1]+ an_x[k+2]+ an_x[k+3]); an_x[k]= n_denom/(int32_t)4; }
    // get difference of smoothed IR signal     for( k=0; k<BUFFER_SIZE-MA4_SIZE-1; k++) an_dx[k]= (an_x[k+1]- an_x[k]);
// 2-pt Moving Average to an_dx for(k=0; k< BUFFER_SIZE-MA4_SIZE-2; k++){ an_dx[k] = ( an_dx[k]+an_dx[k+1])/2 ; } // hamming window // flip wave form so that we can detect valley with peak detector for ( i=0 ; i<BUFFER_SIZE-HAMMING_SIZE-MA4_SIZE-2 ;i++){ s= 0; for( k=i; k<i+ HAMMING_SIZE ;k++){ s -= an_dx[k] *auw_hamm[k-i] ; } an_dx[i]= s/ (int32_t)1146; // divide by sum of auw_hamm     } n_th1=0; // threshold calculation for ( k=0 ; k<BUFFER_SIZE-HAMMING_SIZE ;k++){ n_th1 += ((an_dx[k]>0)? an_dx[k] : ((int32_t)0-an_dx[k])) ; } n_th1= n_th1/ ( BUFFER_SIZE-HAMMING_SIZE); // peak location is acutally index for sharpest location of raw signal since we flipped the signal maxim_find_peaks( an_dx_peak_locs, &n_npks, an_dx, BUFFER_SIZE-HAMMING_SIZE, n_th1, 8, 5 );//peak_height, peak_distance, max_num_peaks
n_peak_interval_sum =0; if (n_npks>=2){ for (k=1; k<n_npks; k++) n_peak_interval_sum += (an_dx_peak_locs[k]-an_dx_peak_locs[k -1]); n_peak_interval_sum=n_peak_interval_sum/(n_npks-1); *pn_heart_rate=(int32_t)(6000/n_peak_interval_sum);// beats per minutes *pch_hr_valid = 1; } else { *pn_heart_rate = -999; *pch_hr_valid = 0; } for ( k=0 ; k<n_npks ;k++)        an_ir_valley_locs[k]=an_dx_peak_locs[k]+HAMMING_SIZE/2
// raw value : RED(=y) and IR(=X) // we need to assess DC and AC value of ir and red PPG. for (k=0 ; k<n_ir_buffer_length ; k++ ) { an_x[k] = pun_ir_buffer[k] ; an_y[k] = pun_red_buffer[k] ; }
// find precise min near an_ir_valley_locs n_exact_ir_valley_locs_count =0; for(k=0 ; k<n_npks ;k++){ un_only_once =1; m=an_ir_valley_locs[k]; n_c_min= 16777216;//2^24; if (m+5 < BUFFER_SIZE-HAMMING_SIZE && m-5 >0){ for(i= m-5;i<m+5; i++) if (an_x[i]<n_c_min){ if (un_only_once >0){ un_only_once =0; } n_c_min= an_x[i] ; an_exact_ir_valley_locs[k]=i; } if (un_only_once ==0) n_exact_ir_valley_locs_count ++ ; } } if (n_exact_ir_valley_locs_count <2 ){ *pn_spo2 = -999 ; // do not use SPO2 since signal ratio is out of range *pch_spo2_valid = 0; return; } // 4 pt MA for(k=0; k< BUFFER_SIZE-MA4_SIZE; k++){ an_x[k]=( an_x[k]+an_x[k+1]+ an_x[k+2]+ an_x[k+3])/(int32_t)4; an_y[k]=( an_y[k]+an_y[k+1]+ an_y[k+2]+ an_y[k+3])/(int32_t)4; }
//using an_exact_ir_valley_locs , find ir-red DC andir-red AC for SPO2 calibration ratio //finding AC/DC maximum of raw ir * red between two valley locations n_ratio_average =0; n_i_ratio_count =0; for(k=0; k< 5; k++) an_ratio[k]=0; for (k=0; k< n_exact_ir_valley_locs_count; k++){ if (an_exact_ir_valley_locs[k] > BUFFER_SIZE ){ *pn_spo2 = -999 ; // do not use SPO2 since valley loc is out of range *pch_spo2_valid = 0; return; } } // find max between two valley locations // and use ratio betwen AC compoent of Ir & Red and DC compoent of Ir & Red for SPO2
for (k=0; k< n_exact_ir_valley_locs_count-1; k++){ n_y_dc_max= -16777216 ; n_x_dc_max= - 16777216; if (an_exact_ir_valley_locs[k+1]-an_exact_ir_valley_locs[k] >10){ for (i=an_exact_ir_valley_locs[k]; i< an_exact_ir_valley_locs[k+1]; i++){ if (an_x[i]> n_x_dc_max) {n_x_dc_max =an_x[i];n_x_dc_max_idx =i; } if (an_y[i]> n_y_dc_max) {n_y_dc_max =an_y[i];n_y_dc_max_idx=i;} } n_y_ac= (an_y[an_exact_ir_valley_locs[k+1]] - an_y[an_exact_ir_valley_locs[k] ] )*(n_y_dc_max_idx -an_exact_ir_valley_locs[k]); //red n_y_ac= an_y[an_exact_ir_valley_locs[k]] + n_y_ac/ (an_exact_ir_valley_locs[k+1] - an_exact_ir_valley_locs[k]) ; n_y_ac= an_y[n_y_dc_max_idx] - n_y_ac; // subracting linear DC compoenents from raw n_x_ac= (an_x[an_exact_ir_valley_locs[k+1]] - an_x[an_exact_ir_valley_locs[k] ] )*(n_x_dc_max_idx -an_exact_ir_valley_locs[k]); // ir n_x_ac= an_x[an_exact_ir_valley_locs[k]] + n_x_ac/ (an_exact_ir_valley_locs[k+1] - an_exact_ir_valley_locs[k]); n_x_ac= an_x[n_y_dc_max_idx] - n_x_ac; // subracting linear DC compoenents from raw n_nume=( n_y_ac *n_x_dc_max)>>7 ; //prepare X100 to preserve floating value n_denom= ( n_x_ac *n_y_dc_max)>>7; if (n_denom>0 && n_i_ratio_count <5 && n_nume != 0) { an_ratio[n_i_ratio_count]= (n_nume*20)/n_denom ; //formular is ( n_y_ac *n_x_dc_max) / ( n_x_ac *n_y_dc_max) ; ///*************************n_nume原來是*100************************// n_i_ratio_count++; } } }
maxim_sort_ascend(an_ratio, n_i_ratio_count); n_middle_idx= n_i_ratio_count/2;
if (n_middle_idx >1) n_ratio_average =( an_ratio[n_middle_idx-1] +an_ratio[n_middle_idx])/2; // use median else n_ratio_average = an_ratio[n_middle_idx ];
if( n_ratio_average>2 && n_ratio_average <184){ n_spo2_calc= uch_spo2_table[n_ratio_average] ; *pn_spo2 = n_spo2_calc ; *pch_spo2_valid = 1;// float_SPO2 = -45.060*n_ratio_average* n_ratio_average/10000 + 30.354 *n_ratio_average/100 + 94.845 ; // for comparison with table } else{ *pn_spo2 = -999 ; // do not use SPO2 since signal ratio is out of range *pch_spo2_valid = 0; }}

注意,這里使用的函數(shù)是SpO2 = -45.060*R*R+ 30.354*R+ 94.845,采用了查表法求解。

這個函數(shù)執(zhí)行完后,變量n_heart_rate中存儲的是心率,變量n_sp02存儲的就是血氧飽和度;

最后將血氧飽和度值顯示出來就行了。

(完整的工程代碼見文末公眾號,關(guān)注后可以找到網(wǎng)盤下載地址)

3)血氧儀測量準(zhǔn)不準(zhǔn)?

實現(xiàn)過程中,SpO2與R的關(guān)系的系數(shù)是非常難確定的,需要大量的試驗數(shù)據(jù)來擬合,見下圖,是maxim公司應(yīng)用文檔中的擬合過程:

(每種顏色是一組測試結(jié)果,黃色叉是去除掉的偏離比較大的野值)

可以發(fā)現(xiàn),有些測量數(shù)據(jù)的方差是相當(dāng)大的,很多數(shù)據(jù)偏離了擬合后的曲線很遠(yuǎn)。maxim公司建議在校準(zhǔn)時,需要不斷剔除偏離較大的數(shù)據(jù),均方根誤差(RMES)需要在3.5%以內(nèi)。

最終給出一組值:

可是,在另一篇maxim公司的應(yīng)用文檔中,又給出了SpO2 = 104-17*R這個公式,其中0.4<R<3.4。

為什么這兩公式相差這么大?

又查閱了一些論文,發(fā)現(xiàn)對于R值與血氧飽和度的公式并不固定,SpO2可以表示為R的一個高次的多項式函數(shù),由于正常人體測出的R值都較小,人們一般關(guān)注的是R值小于1的情況,大于1已經(jīng)是明顯的不健康情況。所以在計算SpO2時常常會去掉高次項,采用一階函數(shù)或者二階函數(shù)來擬合。

又由于SpO2的測量方法本身誤差較大,所以測量數(shù)據(jù)不同時,擬合出來的參數(shù)就大相徑庭了。

這里,我還收集了幾個論文中擬合出的R值與SpO2之間的函數(shù)關(guān)系:

SpO2 = -45.060*R*R+ 30.354*R+ 94.845;

SpO2 = -7.6*R*- 20.7*R+ 112.2;(0.5<R<1.4)

SpO2 = -86.47*R*R+ 77.21*R+ 81.68,(0.4<R<1);

SpO2 = -20*x+107.2,(0.36<R<0.66);-54*x+129.64,(0.66≤R<1)

我把這幾個函數(shù)的圖形繪制在同一張圖中:

可以看到,在R為0.4~1.0這個區(qū)間里,這些函數(shù)的值大體上相差不大,變化趨勢也基本一樣。而且這些參數(shù),一般都是以正常人的數(shù)據(jù)來擬合的,所以在正常血氧的范圍內(nèi),可以認(rèn)為用這種方法來測量血氧飽和度基本靠譜。而當(dāng)血氧飽和度偏離正常值時,誤差會顯著增大。

當(dāng)然,這需要建立在光源的采集數(shù)據(jù)準(zhǔn)確的前提下,也就是R值準(zhǔn)確的時候。

而現(xiàn)實是,在采集光源的數(shù)據(jù)時,會有環(huán)境光干擾、工頻干擾、各種噪聲干擾;即使濾除了這些噪聲,還會有如下圖這種低頻的漂移,此時,要準(zhǔn)確提取出光源的直流分量、交流分量是非常困難的。

因此,如果信號處理的算法不好,就會把微弱的噪聲、漂移等等干擾識別為脈搏引起的光強(qiáng)變化,網(wǎng)上出現(xiàn)的各種能測出香腸的血氧和脈搏的笑話也就不足為奇了。

綜合來看,此類血氧儀作為健康監(jiān)測的參考手段之一是可以的,但是數(shù)據(jù)準(zhǔn)確性存疑,以它來判斷身體是否健康是萬萬不能的。

—— End ——

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
英語前綴大全(按字母排序)
術(shù)中 SpO2 突然掉至 60% …
今日頭條
3
【制表技巧】研究彩票經(jīng)常使用的一些函數(shù)
js生成隨機(jī)數(shù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服