![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
repo time
Dependencies: mbed MAX14720 MAX30205 USBDevice
HspGuiSourceV301/HSPGui/Algorithm/MaximSKAlgorithmClass.cs@20:6d2af70c92ab, 2021-04-06 (annotated)
- Committer:
- darienf
- Date:
- Tue Apr 06 06:41:40 2021 +0000
- Revision:
- 20:6d2af70c92ab
another repo
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
darienf | 20:6d2af70c92ab | 1 | /******************************************************************************* |
darienf | 20:6d2af70c92ab | 2 | * Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved. |
darienf | 20:6d2af70c92ab | 3 | * |
darienf | 20:6d2af70c92ab | 4 | * This software is protected by copyright laws of the United States and |
darienf | 20:6d2af70c92ab | 5 | * of foreign countries. This material may also be protected by patent laws |
darienf | 20:6d2af70c92ab | 6 | * and technology transfer regulations of the United States and of foreign |
darienf | 20:6d2af70c92ab | 7 | * countries. This software is furnished under a license agreement and/or a |
darienf | 20:6d2af70c92ab | 8 | * nondisclosure agreement and may only be used or reproduced in accordance |
darienf | 20:6d2af70c92ab | 9 | * with the terms of those agreements. Dissemination of this information to |
darienf | 20:6d2af70c92ab | 10 | * any party or parties not specified in the license agreement and/or |
darienf | 20:6d2af70c92ab | 11 | * nondisclosure agreement is expressly prohibited. |
darienf | 20:6d2af70c92ab | 12 | * |
darienf | 20:6d2af70c92ab | 13 | * The above copyright notice and this permission notice shall be included |
darienf | 20:6d2af70c92ab | 14 | * in all copies or substantial portions of the Software. |
darienf | 20:6d2af70c92ab | 15 | * |
darienf | 20:6d2af70c92ab | 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
darienf | 20:6d2af70c92ab | 17 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
darienf | 20:6d2af70c92ab | 18 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
darienf | 20:6d2af70c92ab | 19 | * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES |
darienf | 20:6d2af70c92ab | 20 | * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
darienf | 20:6d2af70c92ab | 21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
darienf | 20:6d2af70c92ab | 22 | * OTHER DEALINGS IN THE SOFTWARE. |
darienf | 20:6d2af70c92ab | 23 | * |
darienf | 20:6d2af70c92ab | 24 | * Except as contained in this notice, the name of Maxim Integrated |
darienf | 20:6d2af70c92ab | 25 | * Products, Inc. shall not be used except as stated in the Maxim Integrated |
darienf | 20:6d2af70c92ab | 26 | * Products, Inc. Branding Policy. |
darienf | 20:6d2af70c92ab | 27 | * |
darienf | 20:6d2af70c92ab | 28 | * The mere transfer of this software does not imply any licenses |
darienf | 20:6d2af70c92ab | 29 | * of trade secrets, proprietary technology, copyrights, patents, |
darienf | 20:6d2af70c92ab | 30 | * trademarks, maskwork rights, or any other form of intellectual |
darienf | 20:6d2af70c92ab | 31 | * property whatsoever. Maxim Integrated Products, Inc. retains all |
darienf | 20:6d2af70c92ab | 32 | * ownership rights. |
darienf | 20:6d2af70c92ab | 33 | ******************************************************************************* |
darienf | 20:6d2af70c92ab | 34 | */ |
darienf | 20:6d2af70c92ab | 35 | |
darienf | 20:6d2af70c92ab | 36 | using System; |
darienf | 20:6d2af70c92ab | 37 | using System.Collections; |
darienf | 20:6d2af70c92ab | 38 | using System.Collections.Generic; |
darienf | 20:6d2af70c92ab | 39 | using System.Linq; |
darienf | 20:6d2af70c92ab | 40 | using System.Text; |
darienf | 20:6d2af70c92ab | 41 | |
darienf | 20:6d2af70c92ab | 42 | //------------------------------------------------------------------------------------------ |
darienf | 20:6d2af70c92ab | 43 | // OS24EVK-59 split into HeartRateApp EXE and MAX30101 DLL. |
darienf | 20:6d2af70c92ab | 44 | // Moved all MAX30101 DLL classes into namespace Maxim.MAX30101GUI |
darienf | 20:6d2af70c92ab | 45 | // Moved all HeartRateApp GUI classes into namespace Maxim.MAX30101 |
darienf | 20:6d2af70c92ab | 46 | // OS24EVK-59 Create separate project that builds Maxim.MAX30101GUI DLL library |
darienf | 20:6d2af70c92ab | 47 | |
darienf | 20:6d2af70c92ab | 48 | namespace Maxim.MAX30101GUI |
darienf | 20:6d2af70c92ab | 49 | { |
darienf | 20:6d2af70c92ab | 50 | /// <summary> |
darienf | 20:6d2af70c92ab | 51 | /// Encapsulate the Maxim SKA Algorithm |
darienf | 20:6d2af70c92ab | 52 | /// </summary> |
darienf | 20:6d2af70c92ab | 53 | public class MaximSKAlgorithmClass : MaximAlgorithmClass |
darienf | 20:6d2af70c92ab | 54 | { |
darienf | 20:6d2af70c92ab | 55 | public MaximSKAlgorithmClass() |
darienf | 20:6d2af70c92ab | 56 | { |
darienf | 20:6d2af70c92ab | 57 | // https://jira.maxim-ic.com/browse/OS24EVK-40 remove "algorithm" from algorithm names |
darienf | 20:6d2af70c92ab | 58 | // https://jira.maxim-ic.com/browse/OS24EVK-45 Rename PBA / SKA algorithms |
darienf | 20:6d2af70c92ab | 59 | Name = "Maxim Example Algorithm 2 [SKA.dll]"; |
darienf | 20:6d2af70c92ab | 60 | } |
darienf | 20:6d2af70c92ab | 61 | |
darienf | 20:6d2af70c92ab | 62 | // https://jira.maxim-ic.com/browse/OS24EVK-15 any SKA dependencies? e.g. init MaximSKAlgorithmClass._cboPulseWidthIndex from (byte)(cboPulseWidth.SelectedIndex) |
darienf | 20:6d2af70c92ab | 63 | // public byte _cboPulseWidthIndex = 0; |
darienf | 20:6d2af70c92ab | 64 | |
darienf | 20:6d2af70c92ab | 65 | // Steve Koh's variables |
darienf | 20:6d2af70c92ab | 66 | int _heartRateBPMint; // alias HR |
darienf | 20:6d2af70c92ab | 67 | float _spO2Percentfloat; // alias fSPO2 |
darienf | 20:6d2af70c92ab | 68 | |
darienf | 20:6d2af70c92ab | 69 | const int _SKA_windowSize = 100; |
darienf | 20:6d2af70c92ab | 70 | const int _SKA_bufferSize = 500; |
darienf | 20:6d2af70c92ab | 71 | // https://jira.maxim-ic.com/browse/OS24EVK-15 MaximSKAlgorithmClass accumulate irBuf[0..] _SKA_bufferSize for SKA.SKA_work |
darienf | 20:6d2af70c92ab | 72 | int[] irBuf = new int[_SKA_bufferSize]; |
darienf | 20:6d2af70c92ab | 73 | int[] redBuf = new int[_SKA_bufferSize]; |
darienf | 20:6d2af70c92ab | 74 | int[] greenBuf = new int[_SKA_bufferSize]; |
darienf | 20:6d2af70c92ab | 75 | // https://jira.maxim-ic.com/browse/OS24EVK-35 Support HR from Green LED (SKA) |
darienf | 20:6d2af70c92ab | 76 | ArrayList _SKA_IRList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 77 | ArrayList _SKA_tempIRList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 78 | ArrayList _SKA_redList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 79 | ArrayList _SKA_tempRedList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 80 | ArrayList _SKA_greenList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 81 | ArrayList _SKA_tempGreenList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 82 | int _SKA_numSamplesSinceLastCalc; |
darienf | 20:6d2af70c92ab | 83 | int _SKA_elapsedSecond; |
darienf | 20:6d2af70c92ab | 84 | //int _SKA_validHRcount; |
darienf | 20:6d2af70c92ab | 85 | //int _SKA_invalidHRcount; |
darienf | 20:6d2af70c92ab | 86 | //int _SKA_validSPO2count; |
darienf | 20:6d2af70c92ab | 87 | //int _SKA_invalidSPO2count; |
darienf | 20:6d2af70c92ab | 88 | //int _SKA_lastValidHRtimestamp; |
darienf | 20:6d2af70c92ab | 89 | //int _SKA_lastValidSPO2timestamp; |
darienf | 20:6d2af70c92ab | 90 | // diagnostic: output from SKA algorithm filtering |
darienf | 20:6d2af70c92ab | 91 | float[] irAcBuf = new float[100]; |
darienf | 20:6d2af70c92ab | 92 | float[] redAcBuf = new float[100]; |
darienf | 20:6d2af70c92ab | 93 | // end of Steve Koh's variables |
darienf | 20:6d2af70c92ab | 94 | |
darienf | 20:6d2af70c92ab | 95 | /// <summary> |
darienf | 20:6d2af70c92ab | 96 | /// Clear any internal class members, |
darienf | 20:6d2af70c92ab | 97 | /// in response to startMonitorToolStripMenuItem |
darienf | 20:6d2af70c92ab | 98 | /// </summary> |
darienf | 20:6d2af70c92ab | 99 | override public void Clear() |
darienf | 20:6d2af70c92ab | 100 | { |
darienf | 20:6d2af70c92ab | 101 | _SKA_elapsedSecond = 1; |
darienf | 20:6d2af70c92ab | 102 | //_SKA_lastValidHRtimestamp = 1; |
darienf | 20:6d2af70c92ab | 103 | //_SKA_lastValidSPO2timestamp = 1; |
darienf | 20:6d2af70c92ab | 104 | //_SKA_validHRcount = 0; |
darienf | 20:6d2af70c92ab | 105 | //_SKA_invalidHRcount = 0; |
darienf | 20:6d2af70c92ab | 106 | //_SKA_validSPO2count = 0; |
darienf | 20:6d2af70c92ab | 107 | //_SKA_invalidSPO2count = 0; |
darienf | 20:6d2af70c92ab | 108 | |
darienf | 20:6d2af70c92ab | 109 | _SKA_IRList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 110 | _SKA_tempIRList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 111 | _SKA_redList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 112 | _SKA_tempRedList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 113 | _SKA_greenList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 114 | _SKA_tempGreenList = new ArrayList(); |
darienf | 20:6d2af70c92ab | 115 | _SKA_numSamplesSinceLastCalc = 0; |
darienf | 20:6d2af70c92ab | 116 | // https://jira.maxim-ic.com/browse/OS24EVK-15 SKA need preload _SKA_IRList _SKA_bufferSize in startMonitorToolStripMenuItem_Click |
darienf | 20:6d2af70c92ab | 117 | for (int index = 0; index < _SKA_bufferSize; index++) |
darienf | 20:6d2af70c92ab | 118 | { |
darienf | 20:6d2af70c92ab | 119 | _SKA_IRList.Add(0); |
darienf | 20:6d2af70c92ab | 120 | _SKA_redList.Add(0); |
darienf | 20:6d2af70c92ab | 121 | _SKA_greenList.Add(0); |
darienf | 20:6d2af70c92ab | 122 | } |
darienf | 20:6d2af70c92ab | 123 | } |
darienf | 20:6d2af70c92ab | 124 | |
darienf | 20:6d2af70c92ab | 125 | /// <summary> |
darienf | 20:6d2af70c92ab | 126 | /// <para>InterfaceRedIRGreenLEDdataConsumer</para> |
darienf | 20:6d2af70c92ab | 127 | /// <para>Producer-Consumer data sink for |
darienf | 20:6d2af70c92ab | 128 | /// raw Red/IR/Green LED data. |
darienf | 20:6d2af70c92ab | 129 | /// Produced by MAX30101, consumed by algorithm. |
darienf | 20:6d2af70c92ab | 130 | /// </para> |
darienf | 20:6d2af70c92ab | 131 | /// </summary> |
darienf | 20:6d2af70c92ab | 132 | /// <param name="sampleNumber"></param> |
darienf | 20:6d2af70c92ab | 133 | /// <param name="rawIR"></param> |
darienf | 20:6d2af70c92ab | 134 | /// <param name="rawRed"></param> |
darienf | 20:6d2af70c92ab | 135 | /// <param name="rawGreen"></param> |
darienf | 20:6d2af70c92ab | 136 | /// <param name="rawIRvalid"></param> |
darienf | 20:6d2af70c92ab | 137 | /// <param name="rawRedvalid"></param> |
darienf | 20:6d2af70c92ab | 138 | /// <param name="rawGreenvalid"></param> |
darienf | 20:6d2af70c92ab | 139 | override public void ConsumeRedIRGreenLEDdata( |
darienf | 20:6d2af70c92ab | 140 | int sampleNumber, |
darienf | 20:6d2af70c92ab | 141 | int rawIR, |
darienf | 20:6d2af70c92ab | 142 | int rawRed, |
darienf | 20:6d2af70c92ab | 143 | int rawGreen, |
darienf | 20:6d2af70c92ab | 144 | bool rawIRvalid, |
darienf | 20:6d2af70c92ab | 145 | bool rawRedvalid, |
darienf | 20:6d2af70c92ab | 146 | bool rawGreenvalid |
darienf | 20:6d2af70c92ab | 147 | ) |
darienf | 20:6d2af70c92ab | 148 | { |
darienf | 20:6d2af70c92ab | 149 | base.ConsumeRedIRGreenLEDdata(sampleNumber, rawIR, rawRed, rawGreen, rawIRvalid, rawRedvalid, rawGreenvalid); |
darienf | 20:6d2af70c92ab | 150 | |
darienf | 20:6d2af70c92ab | 151 | bool valid_IR = rawIRvalid; |
darienf | 20:6d2af70c92ab | 152 | bool valid_Red = rawRedvalid; |
darienf | 20:6d2af70c92ab | 153 | bool valid_Green = rawGreenvalid; |
darienf | 20:6d2af70c92ab | 154 | // https://jira.maxim-ic.com/browse/OS24EVK-25 SpO2 mode if LED mode and Red and IR data |
darienf | 20:6d2af70c92ab | 155 | bool HRvalid = (valid_Red || valid_Green); |
darienf | 20:6d2af70c92ab | 156 | bool SPO2valid = (valid_Red && valid_IR); |
darienf | 20:6d2af70c92ab | 157 | // |
darienf | 20:6d2af70c92ab | 158 | // example: https://jira.maxim-ic.com/browse/OS24EVK-37 SpO2 Temperature Compensation |
darienf | 20:6d2af70c92ab | 159 | #region SpO2_Temperature_Compensation |
darienf | 20:6d2af70c92ab | 160 | // SpO2 Temperature Compensation (See MAX30101 data sheet, Applications Information) |
darienf | 20:6d2af70c92ab | 161 | // Estimate red LED temperature rise from peak current and pulse width configuration settings, |
darienf | 20:6d2af70c92ab | 162 | // then use estimated red LED temperature to estimate actual red LED wavelength. |
darienf | 20:6d2af70c92ab | 163 | // |
darienf | 20:6d2af70c92ab | 164 | // double red_LED_temperature_delta = lookup table from peak current and duty cycle |
darienf | 20:6d2af70c92ab | 165 | // See MAX30101 data sheet Table 13. RED LED Current Settings vs LED Temperature Rise |
darienf | 20:6d2af70c92ab | 166 | // |
darienf | 20:6d2af70c92ab | 167 | // double red_LED_temperatureDegreesC = base._temperatureDegreesC + red_LED_temperature_delta; |
darienf | 20:6d2af70c92ab | 168 | // |
darienf | 20:6d2af70c92ab | 169 | // double red_LED_wavelength = lookup table from red_LED_temperatureDegreesC |
darienf | 20:6d2af70c92ab | 170 | // See MAX30101 data sheet toc10 RED LED PEAK WAVELENGTH vs TEMPERATURE |
darienf | 20:6d2af70c92ab | 171 | // |
darienf | 20:6d2af70c92ab | 172 | #endregion SpO2_Temperature_Compensation |
darienf | 20:6d2af70c92ab | 173 | |
darienf | 20:6d2af70c92ab | 174 | double heartRateBPM; // = (double)heartRateBPMint |
darienf | 20:6d2af70c92ab | 175 | bool heartRateBPMValid = false; |
darienf | 20:6d2af70c92ab | 176 | double heartRateBPMSignalStrength = 0; |
darienf | 20:6d2af70c92ab | 177 | double spO2Percent; // = (double)spO2Percentfloat |
darienf | 20:6d2af70c92ab | 178 | bool spO2PercentValid = false; |
darienf | 20:6d2af70c92ab | 179 | double spO2PercentSignalStrength = 0; // = (double)SPO2error |
darienf | 20:6d2af70c92ab | 180 | float SPO2error = 0; |
darienf | 20:6d2af70c92ab | 181 | // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass |
darienf | 20:6d2af70c92ab | 182 | |
darienf | 20:6d2af70c92ab | 183 | // https://jira.maxim-ic.com/browse/OS24EVK-15 MaximSKAlgorithmClass accumulate irBuf[0..] _SKA_bufferSize for SKA.SKA_work |
darienf | 20:6d2af70c92ab | 184 | // int[] irBuf = new int[_SKA_bufferSize]; |
darienf | 20:6d2af70c92ab | 185 | // int[] redBuf = new int[_SKA_bufferSize]; |
darienf | 20:6d2af70c92ab | 186 | for (int index = 0; index < _SKA_tempRedList.Count; index++) |
darienf | 20:6d2af70c92ab | 187 | { |
darienf | 20:6d2af70c92ab | 188 | _SKA_IRList.Add((int)_SKA_tempIRList[index]); |
darienf | 20:6d2af70c92ab | 189 | _SKA_IRList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 190 | _SKA_redList.Add((int)_SKA_tempRedList[index]); |
darienf | 20:6d2af70c92ab | 191 | _SKA_redList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 192 | _SKA_greenList.Add((int)_SKA_tempGreenList[index]); |
darienf | 20:6d2af70c92ab | 193 | _SKA_greenList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 194 | _SKA_numSamplesSinceLastCalc++; |
darienf | 20:6d2af70c92ab | 195 | } |
darienf | 20:6d2af70c92ab | 196 | _SKA_tempIRList.Clear(); |
darienf | 20:6d2af70c92ab | 197 | _SKA_tempRedList.Clear(); |
darienf | 20:6d2af70c92ab | 198 | _SKA_tempGreenList.Clear(); |
darienf | 20:6d2af70c92ab | 199 | // |
darienf | 20:6d2af70c92ab | 200 | if (_SKA_numSamplesSinceLastCalc < _SKA_windowSize) |
darienf | 20:6d2af70c92ab | 201 | { |
darienf | 20:6d2af70c92ab | 202 | _SKA_IRList.Add(rawIR); |
darienf | 20:6d2af70c92ab | 203 | _SKA_IRList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 204 | _SKA_redList.Add(rawRed); |
darienf | 20:6d2af70c92ab | 205 | _SKA_redList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 206 | _SKA_greenList.Add(rawGreen); |
darienf | 20:6d2af70c92ab | 207 | _SKA_greenList.RemoveAt(0); |
darienf | 20:6d2af70c92ab | 208 | } |
darienf | 20:6d2af70c92ab | 209 | else |
darienf | 20:6d2af70c92ab | 210 | { |
darienf | 20:6d2af70c92ab | 211 | _SKA_tempIRList.Add(rawIR); |
darienf | 20:6d2af70c92ab | 212 | _SKA_tempRedList.Add(rawRed); |
darienf | 20:6d2af70c92ab | 213 | _SKA_tempGreenList.Add(rawGreen); |
darienf | 20:6d2af70c92ab | 214 | } |
darienf | 20:6d2af70c92ab | 215 | _SKA_numSamplesSinceLastCalc++; |
darienf | 20:6d2af70c92ab | 216 | // |
darienf | 20:6d2af70c92ab | 217 | if (_SKA_numSamplesSinceLastCalc >= _SKA_windowSize) |
darienf | 20:6d2af70c92ab | 218 | { |
darienf | 20:6d2af70c92ab | 219 | _SKA_numSamplesSinceLastCalc = 0; |
darienf | 20:6d2af70c92ab | 220 | for (int index = 0; index < _SKA_IRList.Count; index++) |
darienf | 20:6d2af70c92ab | 221 | { |
darienf | 20:6d2af70c92ab | 222 | irBuf[index] = (int)_SKA_IRList[index]; |
darienf | 20:6d2af70c92ab | 223 | redBuf[index] = (int)_SKA_redList[index]; |
darienf | 20:6d2af70c92ab | 224 | greenBuf[index] = (int)_SKA_greenList[index]; |
darienf | 20:6d2af70c92ab | 225 | } |
darienf | 20:6d2af70c92ab | 226 | |
darienf | 20:6d2af70c92ab | 227 | // Steve Koh's algorithm uses Fs=100Sps. It processes 500 samples at a time. Shift in 100 new samples before the function is called. |
darienf | 20:6d2af70c92ab | 228 | // Since we're running at 100Sps, this routine is called every 100 samples. |
darienf | 20:6d2af70c92ab | 229 | // Although _SKA_elapsedSecond = num samples / Fs, Steve used an integer type and so only Fs=100Sps or 50Sps would work. Regardless, we are using fixed 100Sps. |
darienf | 20:6d2af70c92ab | 230 | // |
darienf | 20:6d2af70c92ab | 231 | // Heart Rate/SpO2 Monitor function takes 18bit input irBuffer[500] and redBuffer[500]. |
darienf | 20:6d2af70c92ab | 232 | // Inputs: |
darienf | 20:6d2af70c92ab | 233 | // int lapsedSecond -> _SKA_elapsedSecond must be >3 before anything happens |
darienf | 20:6d2af70c92ab | 234 | // const int irBuffer[500] -> irBuf |
darienf | 20:6d2af70c92ab | 235 | // const int redBuffer[500] -> redBuf |
darienf | 20:6d2af70c92ab | 236 | // Outputs: |
darienf | 20:6d2af70c92ab | 237 | // unsigned int *heartRate -> HR Heart Rate in beats per minute. |
darienf | 20:6d2af70c92ab | 238 | // float *SPO2 -> fSPO2 SpO2 value as %saturation. |
darienf | 20:6d2af70c92ab | 239 | // boolean_T *SPO2valid -> SPO2valid |
darienf | 20:6d2af70c92ab | 240 | // boolean_T *HRvalid -> HRvalid |
darienf | 20:6d2af70c92ab | 241 | // float *SPO2errorStatus -> SPO2error looks like a signal strength? |
darienf | 20:6d2af70c92ab | 242 | // float last100Ir[100] -> irAcBuf |
darienf | 20:6d2af70c92ab | 243 | // float last100Red[100] -> redAcBuf |
darienf | 20:6d2af70c92ab | 244 | // |
darienf | 20:6d2af70c92ab | 245 | if (valid_Green && !valid_IR) // Green mode - green into IR channel |
darienf | 20:6d2af70c92ab | 246 | { |
darienf | 20:6d2af70c92ab | 247 | // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass |
darienf | 20:6d2af70c92ab | 248 | // https://jira.maxim-ic.com/browse/OS24EVK-35 Support HR from Green LED (SKA Algorithm) |
darienf | 20:6d2af70c92ab | 249 | // for SKA green LED support, looks like we have to preload redBuf with Green LED data... |
darienf | 20:6d2af70c92ab | 250 | // no IR, but we can use Green instead for HR. (No SpO2 measurement so both channels Green.) |
darienf | 20:6d2af70c92ab | 251 | SKA.SKA_work( |
darienf | 20:6d2af70c92ab | 252 | _SKA_elapsedSecond, |
darienf | 20:6d2af70c92ab | 253 | greenBuf, |
darienf | 20:6d2af70c92ab | 254 | greenBuf, |
darienf | 20:6d2af70c92ab | 255 | ref _heartRateBPMint, |
darienf | 20:6d2af70c92ab | 256 | ref _spO2Percentfloat, |
darienf | 20:6d2af70c92ab | 257 | ref spO2PercentValid, |
darienf | 20:6d2af70c92ab | 258 | ref heartRateBPMValid, |
darienf | 20:6d2af70c92ab | 259 | ref SPO2error, |
darienf | 20:6d2af70c92ab | 260 | irAcBuf, |
darienf | 20:6d2af70c92ab | 261 | redAcBuf); |
darienf | 20:6d2af70c92ab | 262 | } |
darienf | 20:6d2af70c92ab | 263 | else if (valid_Red && !valid_IR && !valid_Green) // HR mode - red into IR channel |
darienf | 20:6d2af70c92ab | 264 | { |
darienf | 20:6d2af70c92ab | 265 | SKA.SKA_work( |
darienf | 20:6d2af70c92ab | 266 | _SKA_elapsedSecond, |
darienf | 20:6d2af70c92ab | 267 | redBuf, |
darienf | 20:6d2af70c92ab | 268 | redBuf, |
darienf | 20:6d2af70c92ab | 269 | ref _heartRateBPMint, |
darienf | 20:6d2af70c92ab | 270 | ref _spO2Percentfloat, |
darienf | 20:6d2af70c92ab | 271 | ref spO2PercentValid, |
darienf | 20:6d2af70c92ab | 272 | ref heartRateBPMValid, |
darienf | 20:6d2af70c92ab | 273 | ref SPO2error, |
darienf | 20:6d2af70c92ab | 274 | irAcBuf, |
darienf | 20:6d2af70c92ab | 275 | redAcBuf); |
darienf | 20:6d2af70c92ab | 276 | } |
darienf | 20:6d2af70c92ab | 277 | else // SpO2 mode |
darienf | 20:6d2af70c92ab | 278 | { |
darienf | 20:6d2af70c92ab | 279 | // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass |
darienf | 20:6d2af70c92ab | 280 | // normal HR from Red, SpO2 if IR is available |
darienf | 20:6d2af70c92ab | 281 | // SKA.SKA_work(_SKA_elapsedSecond, irBuf, redBuf, ref HR, ref fSPO2, ref SPO2valid, ref HRvalid, ref SPO2error, irAcBuf, redAcBuf); |
darienf | 20:6d2af70c92ab | 282 | SKA.SKA_work( |
darienf | 20:6d2af70c92ab | 283 | _SKA_elapsedSecond, |
darienf | 20:6d2af70c92ab | 284 | irBuf, |
darienf | 20:6d2af70c92ab | 285 | redBuf, |
darienf | 20:6d2af70c92ab | 286 | ref _heartRateBPMint, |
darienf | 20:6d2af70c92ab | 287 | ref _spO2Percentfloat, |
darienf | 20:6d2af70c92ab | 288 | ref spO2PercentValid, |
darienf | 20:6d2af70c92ab | 289 | ref heartRateBPMValid, |
darienf | 20:6d2af70c92ab | 290 | ref SPO2error, |
darienf | 20:6d2af70c92ab | 291 | irAcBuf, |
darienf | 20:6d2af70c92ab | 292 | redAcBuf); |
darienf | 20:6d2af70c92ab | 293 | } |
darienf | 20:6d2af70c92ab | 294 | _SKA_elapsedSecond++; |
darienf | 20:6d2af70c92ab | 295 | |
darienf | 20:6d2af70c92ab | 296 | |
darienf | 20:6d2af70c92ab | 297 | // https://jira.maxim-ic.com/browse/OS24EVK-15 SKA algorithm report results by InterfaceHeartRateSpO2dataConsumer.ConsumeHeartRateSpO2data(heartRateBPM, ...) |
darienf | 20:6d2af70c92ab | 298 | heartRateBPM = (double)_heartRateBPMint; |
darienf | 20:6d2af70c92ab | 299 | spO2Percent = (double)_spO2Percentfloat; |
darienf | 20:6d2af70c92ab | 300 | // OS24EVK-35 don't report SpO2 if there was not valid red and IR data (i.e. green only) |
darienf | 20:6d2af70c92ab | 301 | if (!(valid_Red && valid_IR)) { spO2PercentValid = false; } |
darienf | 20:6d2af70c92ab | 302 | spO2PercentSignalStrength = (double)SPO2error; |
darienf | 20:6d2af70c92ab | 303 | // https://jira.maxim-ic.com/browse/OS24EVK-15 SKAAlgorithm reporting SpO2 999 as if that was valid. |
darienf | 20:6d2af70c92ab | 304 | // SKA Algorithm reports SpO2 bogus value 999% as valid; need to determine why reported as a valid result. |
darienf | 20:6d2af70c92ab | 305 | // spO2PercentValid = (spO2PercentSignalStrength > 0); |
darienf | 20:6d2af70c92ab | 306 | // don't modify spO2PercentValid; already passed by ref from SKA.SKA_work() |
darienf | 20:6d2af70c92ab | 307 | ReportResultsHeartRateSpO2dataAvailable(heartRateBPM, heartRateBPMValid, heartRateBPMSignalStrength, spO2Percent, spO2PercentValid, spO2PercentSignalStrength); |
darienf | 20:6d2af70c92ab | 308 | System.Diagnostics.Debug.Print("heartRateBPM: " + heartRateBPM + " heartRateBPMValid: " + heartRateBPMValid + " spO2Percent: " + spO2Percent + " spO2PercentValid: " + spO2PercentValid); |
darienf | 20:6d2af70c92ab | 309 | } // if (_SKA_numSamplesSinceLastCalc >= _SKA_windowSize) |
darienf | 20:6d2af70c92ab | 310 | } |
darienf | 20:6d2af70c92ab | 311 | |
darienf | 20:6d2af70c92ab | 312 | } |
darienf | 20:6d2af70c92ab | 313 | } |