脈搏血氧儀可測量外周血氧飽和度 (SpO2),該指標反映了心肺系統向身體提供富氧血液的效率。運動員使用 SpO2 測量值來衡量他們在鍛煉中的努力程度,但這種測量在新冠肺炎流行期間變得更加重要。醫護人員很關注 SpO2 的下降,因為它是引起新冠肺炎的 SARS-CoV-2 病毒對肺組織造成損傷的預警信號。 對于被要求在家中隔離的癥狀輕微的感染者來說,如果有一臺低成本脈搏血氧儀隨時可以使用,那么將有助于判斷病情并獲得及時就醫所需的警告信息。 本文簡要討論了新冠肺炎的癥狀和監測 SpO2 的需求。然后向開發人員展示如何使用 Microchip Technology 數字信號控制器 (DSC) 和一些附加器件,設計一個低成本的脈搏血氧儀,從而針對新冠肺炎感染后期的癥狀,為家庭用戶提供預警。 新冠肺炎和測量血氧飽和度的需求 由于 SARS-CoV-2 病毒的破壞作用,新冠肺炎會表現出各種癥狀。對于醫護人員來說,一個特別令人擔憂的癥狀與肺組織損傷有關,它將導致呼吸系統受損,攝氧量減少。盡管醫生會逐一使用胸部 X 光檢查和計算機斷層 (CT) 掃描來確認這一階段的新冠肺炎,但他們往往會使用 SpO2 測量值作為早期指標。 通過由患者動脈抽取樣本并分析血氣水平,可直接確定動脈血氧飽和度 (SaO2),而 SpO2 測量是一種非侵入式的替代測量方法。雖然某些情況下可能需要直接測量動脈血氣,但 SpO2 測量已被證明可以提供可靠的 SaO2 估計值。也許最重要的是,在家即可使用光學脈搏血氧儀進行測量,而測量結果跟臨床環境一樣可靠。 光學脈搏血氧儀利用脫氧血紅蛋白 (Hb) 和氧合血紅蛋白 (HbO2) 的光吸收差異來測量 SpO2。在富含氧氣的肺內,紅細胞中的血紅蛋白最多可與四個氧分子迅速形成可逆性結合,從而生成 HbO2,該分子對波長為 940 nm 的光吸收率高于波長為 660 nm 的光(圖 1)。 ![]() 圖 1:脈搏血氧儀利用了氧合血紅蛋白 (HbO2) 與脫氧血紅蛋白 (Hb) 吸收光譜之間的差異。(圖片來源:維基百科) 當攜帶 HbO2 的紅細胞通過外周血管時,血氧分壓(混合氣體中單一氣體成分的壓力)較低,血紅蛋白對氧的親和力下降,HbO2 開始釋放氧分子,最終成為 Hb。在這種脫氧狀態下,該分子的吸收光譜發生改變,對波長為 660 nm 的光吸收率高于波長為 940 nm 的光。 因為 HbO2 在血氧分壓較低時會變為 Hb,所以 SpO2 可以用簡單的公式來確定: SpO2 = HbO2 / (HbO2 + Hb) 血液中 Hb 和 HbO2 的相對濃度則可通過測量對波長為 660 nm 和 940 nm 的光吸收情況來確定。 脈搏血氧儀利用血氧分壓、血紅蛋白氧結合狀態和光吸收差異之間的關系,可提供可靠的 SpO2 測量。 典型脈搏血氧儀的主要子系統 典型脈搏血氧儀設計包括三個主要子系統: · 光傳輸子系統,包括模擬開關和驅動器,以及可發出紅光(波長為 660 nm)和紅外線 (IR)(波長為 950 nm)的發光二極管 (LED)。一些系統還包括綠光(波長為 530 nm)光源,可配合光電容積描記法 (PPG) 使用,通過監測皮膚血管容積的變化來確定心率。 · 光檢測子系統,包括光電二極管、信號調節鏈和模數轉換器 (ADC)。 · DSC 或微控制器,用于協調光傳輸和光檢測子系統,并由測得的數據計算 SpO2。 盡管任何脈搏血氧儀中都存在這些基本子系統,但它們的實現方式可能千差萬別。對于透射式脈搏血氧儀,光電二極管與 LED 分別放置在用戶手指或耳垂的兩側。常見的指夾裝置一側裝有紅光、紅外光 和綠光(可選)LED,另一側則是光電二極管。對于反射式脈搏血氧儀,光電二極管和 LED 均放置在皮膚的同一側,兩者之間需設置光學屏障以減少偽影。例如,OSRAM 的 SFH7060 是一款即用型反射式測量器件,在單個封裝中包含 LED 和光電二極管,尺寸僅為 7.2 x 2.5 x 0.9 mm。 無論是將這些采用光學封裝結構的器件用于透射式測量,還是反射式測量,設計人員都只需要添加相對較少的元器件就可實現低成本的脈搏血氧儀設計,并且能夠為家庭用戶提供相關信息,針對是否需要專業醫護人員進一步評估提出建議。在基于 Microchip Technology 的 DSPIC33FJ128GP802 DSC 構建的設計示例中,使用微控制器的集成外設來控制紅光和紅外光 LED 對皮膚的照射,然后將調節后的光電二極管輸出信號數字化(圖 2)。 ![]() 圖 2:在典型脈搏血氧儀設計中,往往集成了 LED 照射子系統和光電二極管信號處理子系統,以及控制照射時序和數據采集的微控制器。(圖片來源:Microchip Technology) 無論光源類型如何,脈搏血氧儀設計通常依靠具有寬光譜響應范圍的單個光電二極管,以捕獲透射或反射信號。為了確保接收到的信號僅對應于紅光或紅外光波長,硬件或軟件控制邏輯在給定時間內僅開啟紅光或紅外光源,兩個光源交替發光以完成測量序列。 實現低成本脈搏血氧儀硬件設計 在此設計中,DSC 使用外部 Microchip Technology 的 MCP4728 數模轉換器 (DAC) 將單獨的 MBT2222 晶體管置于所需電平,從而以所需的亮度驅動各個 LED。為了對每個 LED 的“開啟”序列進行精確定時,DSC 使用其中兩個脈沖寬度調制 (PWM) 輸出來控制 Analog Devices 的 ADG884 模擬開關(圖 3)。 ![]() 圖 3:模擬開關由數字控制器紅光和紅外光通道的交替信號驅動,用于產生紅光和紅外光 LED 的驅動電流。(圖片來源:Microchip Technology) 為了處理光電二極管輸出,單個 Microchip Technology 的 MCP6002 器件可提供一對運算放大器,借以實現基本兩級信號調節鏈。在這里,第一級使用 MCP6002 的一個運算放大器,將其配置為跨阻放大器,以便將光電二極管的電流輸出轉換為電壓信號。在經過高通濾波器以降低噪聲后,MCP6002 中的第二個運算放大器提供了增益和直流偏移調整,以在 DSC 集成的 ADC 全范圍內優化調節后信號的擺動(圖 4)。 ![]() 圖 4:兩級信號鏈調節光電二極管輸出,以實現到數字控制器的集成 ADC 的信號傳送。(圖片來源:Microchip Technology) 工作時,DSC 使用其 PWM 輸出和 ADC 輸入,對調節后光電二極管輸出信號的 LED 照射和 ADC 數字化進行同步。這樣,每個交替的紅光和紅外光照射周期都會配合信號采集和轉換。在兩個 LED 都關閉時,還需采集一個 ADC 樣本以測量環境光,以便用于優化 LED 亮度和 SpO2 測量。最后得到的是一個精確控制的事件序列,協調 LED 照射與 ADC 數字化,以捕獲表示 Hb 的紅光波長結果,再捕獲環境光,最終捕獲表示 HbO2 的紅外光波長結果(圖 5)。 ![]() 圖 5:低成本脈搏血氧儀的功能依賴于數字信號控制器的管理能力,控制器需要對照射時序和數據捕獲進行精確定時,才能收集測量值以確定 SpO2。(圖片來源:Microchip Technology) 實現中斷驅動軟件解決方案 Microchip 提供的脈搏血氧儀固件包帶有一個樣例程序,演示了如何使用 DSC 執行這些照射控制和數據轉換序列。在這里,該程序使用一對 DSC 定時器(Timer2 和 Timer3)來實現中斷驅動方法,這兩個定時器分別用于紅外光 LED 和紅光 LED 各自的“開啟”序列。這樣,每個定時器又為 DSC 的兩個輸出比較 (OC) 模塊(OC1 和 OC2)提供時基,這兩個模塊分別用于控制紅外光LED 和紅光 LED 的模擬開關。 如清單 1 所示,該軟件首先初始化 Timer2 和 Timer3,以設置所需的照射周期時長并啟用中斷。作為其初始化序列的一部分,OC1 和 OC2 模塊使用 DSC 的可重映射引腳 (RP) 功能連接到各自的輸出引腳。然后,初始化序列設置照射占空比,并選擇關聯定時器用作時基。 副本 //********************************************************************************************************* // Initialize Timer 2 - IR light //********************************************************************************************************* T2CON = 0x0020; // Stop 16-bit Timer2, 1:64(40MhzFosc) Prescale, Internal clock (Fosc/2) TMR2 = 0x00; // Clear timer register PR2 = 1250; // Load the period value, OCxRS <= PRx, 4ms period = (1/(Fosc/2))*1000*64*PR2 = (1/(40000000/2))*1000*64*1250 IPC1bits.T2IP = 2; // Set Timer2 Interrupt Priority Level IFS0bits.T2IF = 0; // Clear Timer2 Interrupt Flag IEC0bits.T2IE = 1; // Enable Timer2 Interrupt //********************************************************************************************************* // Initialize Timer 3 - Red light //********************************************************************************************************* T3CON = 0x0020; // Stop 16-bit Timer3, 1:64(40MhzFosc) Prescale, Internal clock (Fosc/2) TMR3 = 0x00; // Clear timer register PR3 = 1250; // Load the period value, OCxRS <= PRx, 4ms period = (1/(Fosc/2))*1000*64*PR2 = (1/(40000000/2))*1000*64*1250 IPC2bits.T3IP = 2; // Set Timer3 Interrupt Priority Level IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag IEC0bits.T3IE = 1; // Enable Timer3 Interrupt //********************************************************************************************************* // Initialize Output Compare 1 module in Continuous Pulse mode, OC1 controls IR LED switch //********************************************************************************************************* RPOR6bits.RP13R = 0b10010; // RP13/RB13 tied to OC1 (IR) OC1CONbits.OCM = 0b000; // Disable Output Compare 1 Module OC1R = 0; // Write the duty cycle for the first PWM pulse, 24=8MHzFosc(50us), 30=40MHzFosc(50us), 600=40MHzFosc(1ms) OC1RS = duty_cycle; // Write the duty cycle for the second PWM pulse, OCxRS <= PRx, 499=8MHzFosc(1ms), 623=40MHzFosc(1ms), 1246=40MHzFoc,2msPeriod, 4984=40MHzFoc,8msPeriod, 280=450us D/C@40MHzFoc,2msPeriod,switch OC1CONbits.OCTSEL = 0; // Select Timer 2 as output compare time base //********************************************************************************************************* // Initialize Output Compare 2 module in Continuous Pulse mode, OC2 controls Red LED switch //********************************************************************************************************* RPOR6bits.RP12R = 0b10011; // RP12/RB12 tied to OC2 (Red) OC2CONbits.OCM = 0b000; // Disable Output Compare 2 Module OC2R = 0; // Write the duty cycle for the first PWM pulse, 24=8MHzFosc, 30=40MHzFosc, 600=40MHzFosc(1ms) OC2RS = duty_cycle; // Write the duty cycle for the second PWM pulse, OCxRS <= PRx, 499=8MHzFosc(1ms), 623=40MHzFosc(1ms), 1246=40MHzFoc,2msPeriod, 4984=40MHzFoc,8msPeriod, 280=450us D/C@40MHzFoc,2msPeriod,switch OC2CONbits.OCTSEL = 1; // Select Timer 3 as output compare time base 清單 1:在 Microchip Technology 提供的示例代碼包中,主例程使用一個簡短的初始化序列來設置數字信號控制器的定時器和輸出比較模塊,這是這種低成本脈搏血氧儀解決方案的核心。(代碼來源:Microchip Technology) 這種方法利用了 DSC 架構將每個定時器中斷與特定的中斷服務例程 (ISR) 入口點相關聯的特性。例如,當紅光 LED 通道的 Timer3 中斷發生時,DSC 在 _T3Interrupt 入口點執行相應功能。因此,當紅光 LED 的 Timer3 到期時,會發生以下兩個相應的硬件和軟件事件: OC2 生成一個連續脈沖并發送至模擬開關,開啟紅光 LED DSC 開始執行 _T3Interrupt ISR(清單 2) 副本 void __attribute__((__interrupt__, no_auto_psv)) _T3Interrupt(void) //Read Red DC & AC signals from AN0 & AN1 { int delay; unsigned char i; Read_ADC_Red = 1; CH0_ADRES_Red_sum = 0; CH1_ADRES_Red_sum = 0; for (delay=0; delay<200; delay++); //2000=delayed 256us before read ADC // LATBbits.LATB14 = 1; // for debugging for (i=0; i //Acquires Red-DC from Channel0 (AN0) AD1CHS0bits.CH0SA = 0x00; // Select AN0 AD1CON1bits.SAMP = 1; // Begin sampling while(!AD1CON1bits.DONE); // Waiting for ADC completed AD1CON1bits.DONE = 0; // Clear conversion done status bit CH0_ADRES_Red_sum = CH0_ADRES_Red_sum + ADC1BUF0; // Read ADC result //Acquires Red-AC from Channel1 (AN1) AD1CHS0bits.CH0SA = 0x01; // Select AN1 AD1CON1bits.SAMP = 1; // Begin sampling while(!AD1CON1bits.DONE); // Waiting for ADC completed AD1CON1bits.DONE = 0; // Clear conversion done status bit CH1_ADRES_Red_sum = CH1_ADRES_Red_sum + ADC1BUF0; // Read ADC result } CH0_ADRES_Red = CH0_ADRES_Red_sum / oversampling_number; FIR_input_Red[0] = CH1_ADRES_Red_sum / oversampling_number; #ifdef Sleep_Enabled if (CH0_ADRES_Red<=74 && CH1_ADRES_Red>=4000) //if spo2 probe is not connected, 74=60mV, 4000=3.2V { goto_sleep = 1; } else if (CH0_ADRES_Red > Finger_Present_Threshold) //if no finger present then goto sleep { goto_sleep = 1; } else #endif { // LATBbits.LATB14 = 0; // for debugging for (delay=0; delay<500; delay++); //1000=delayed 256us before read ADC // LATBbits.LATB14 = 1; // for debugging //Acquires Red-DC baseline from Channel0 (AN0) AD1CHS0bits.CH0SA = 0x00; // Select AN0 AD1CON1bits.SAMP = 1; // Begin sampling while(!AD1CON1bits.DONE); // Waiting for ADC completed AD1CON1bits.DONE = 0; // Clear conversion done status bit Baseline_ambient = ADC1BUF0; Baseline_Upper_Limit = Baseline_ambient + DCVppHigh; Baseline_Lower_Limit = Baseline_ambient + DCVppLow; Meter_State = Calibrate_Red(); } // LATBbits.LATB14 = 0; // for debugging OC2RS = duty_cycle; // Write Duty Cycle value for next PWM cycle IFS0bits.T3IF = 0; // Clear Timer3 Interrupt Flag } 清單 2:Microchip Technology 的示例代碼包含有此處所示的 Timer3 ISR,這段代碼用于收集紅光 LED 照射的測量值和環境光測量值,而 Timer2 ISR 只需要收集紅外光 LED 照射的測量值。(代碼來源:Microchip Technology) 如清單 2 所示,_T3Interrupt ISR 從 ADC 通道 0 (AN0) 讀取紅光基線水平 (Red-DC),并從 ADC 通道 1 (AN1) 讀取紅光動態水平 (Red-AC)。如果開發人員選擇將 Sleep_Enabled 的定義納入應用中,則編譯的 ISR 代碼會在捕獲數據后檢查處理器是否應進入休眠狀態。Microchip 軟件包的默認配置包括 Sleep_Enabled 的 #define,因此如果未連接光學探頭或者未檢測到用戶的手指,則將設置變量 goto_sleep。 檢查了此探頭狀態之后,ISR 會對環境光水平進行采樣,并使用此更新值相應地調整基線窗口限值。利用這些調整后的限值,函數 Calibrate_Red() 可增加或減少連接紅光 LED 驅動器的 DAC 輸出,使亮度保持在 Baseline_Lower_Limit 和 Baseline_Upper_Limit 之間。 T2 定時器中斷服務例程使用相同的基本設計模式,但不包括對 sleep_enabled 和環境光水平測量值的檢查。 配置了定時器、輸出比較和 ISR 后,該示例軟件的主例程將執行一個簡短的初始化序列,并啟動 Timer2 和 Timer3。此時,代碼進入主循環,等待接收 ISR 處理的數據。待獲得紅光和紅外光數據后,這些值將由一個數字有限脈沖響應 (FIR) 濾波器進行處理,最后調用例程來計算 SpO2 和心率(清單 3)。 副本 //********** Enable OC1 & OC2 ouputs for IR & Red LED's on/off switch ********** OC2CONbits.OCM = 0b101; // Select the Output Compare 2 mode, Turn on Red LED T3CONbits.TON = 1; // Start Timer3 for (delay=0; delay<2200; delay++); OC1CONbits.OCM = 0b101; // Select the Output Compare 1 mode, Turn on IR LED T2CONbits.TON = 1; // Start Timer2 goto_sleep = 0; first_reading = 0; while (1) { if (goto_sleep) { [lines clipped] Sleep(); // Put MCU into sleep Nop(); } } //--------- Main State Machine starts here --------- if (RedReady && IRReady) { RedReady = 0; IRReady = 0; // LATBbits.LATB14 = 1; //for debugging FIR(1, &FIR_output_IR[0], &FIR_input_IR[0], &BandpassIRFilter); FIR(1, &FIR_output_Red[0], &FIR_input_Red[0], &BandpassRedFilter); CH1_ADRES_IR = FIR_output_IR[0]; CH1_ADRES_Red = FIR_output_Red[0]; [lines clipped] if (Detection_Done) { //Max & Min are all found. Calculate SpO2 & Pulse Rate SpO2_Calculation(); //calculate SpO2 Pulse_Rate_Calculation(); //calculate pulse rate [lines clipped] } /***************************************************************************** * Function Name: SpO2_Calculation() * Specification: Calculate the %SpO2 *****************************************************************************/ void SpO2_Calculation (void) { double Ratio_temp; IR_Vpp1 = fabs(IR_Max - IR_Min); Red_Vpp1 = fabs(Red_Max - Red_Min); IR_Vpp2 = fabs(IR_Max2 - IR_Min2); Red_Vpp2 = fabs(Red_Max2 - Red_Min2); IR_Vpp = (IR_Vpp1 + IR_Vpp2) / 2; Red_Vpp = (Red_Vpp1 + Red_Vpp2) / 2; IR_Vrms = IR_Vpp / sqrt(8); Red_Vrms = Red_Vpp / sqrt(8); // SpO2 = log10(Red_Vrms) / log10(IR_Vrms) * 100; // if (SpO2 > 100) // { // SpO2 = 100; // } // Using lookup table to calculate SpO2 Ratio = (Red_Vrms/CH0_ADRES_Red) / (IR_Vrms/CH0_ADRES_IR); 清單 3:在 Microchip Technology 示例代碼包中,主例程的這段代碼展示了該代碼如何初始化定時器和輸出比較模塊并進入無限循環,從而在獲得測量值后計算 SpO2 和心率,或在未連接傳感器時將處理器置于低功耗休眠模式。(代碼來源:Microchip Technology) 對于 SpO2,函數 SpO2_Calculation() 將紅光和紅外光信號的脈沖幅度 (Vpp) 轉換為 Vrms 值。該函數使用這些值生成一個比值,并使用查找表(清單 3 中未顯示)將該比值轉換為特定的 SpO2 值。通常,該查找表由多次測量經驗總結得出。Pulse_Rate_Calculation() 使用測量的峰間計時來確定心率。 SpO2 設計優化選項 雖然本文介紹的設計為低成本脈搏血氧儀提供了一個有效的解決方案,但其他器件可能會提供進一步的優化。例如,開發人員可以使用 Microchip Technology 的 DSPIC33CK64MP102 DSC 集成的運算放大器,則無需添加外部 MCP6002 雙運算放大器器件。 然而,在實現這種經過修改的脈搏血氧儀設計時,由于 DSC 有所不同,開發人員需要重寫以上軟件包的一些關鍵部分。 例如,不同于 DSPIC33FJ128GP802 DSC 中的 Timer2/Timer3 功能,DSPIC33CK64MP102 DSC 提供了一組多用途定時器模塊,因此需要開發人員提供自己的解決方案,以實現本文清單中所述的某些功能。即便如此,工作原理依然不變,開發人員至少可以使用 Microchip Technology 示例軟件包所示的設計模式來指導自己的定制軟件設計。 結語 血氧飽和度測量可提供重要的呼吸功能指標,在新冠肺炎疫情期間已成為重要的健康管理工具。使用簡單的光學方法,脈搏血氧儀提供了可靠的外周血氧飽和度 (SpO2) 估計值,可滿足疫情期間對平價健康監測解決方案的特別需求。 如上所述,DSC 與一些基本元器件相結合,為實現低成本的脈搏血氧儀提供了有效的硬件基礎,能夠提供可靠的 SpO2 測量值,從而針對是否需要尋求進一步醫療護理以診治不斷加重的新冠肺炎感染,為用戶提供必要信息。 來源:Digi-Key 作者:Stephen Evanczuk |