Darien Figueroa / Mbed 2 deprecated repo3

Dependencies:   mbed MAX14720 MAX30205 USBDevice

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MaximSKAlgorithmClass.cs Source File

MaximSKAlgorithmClass.cs

00001 /*******************************************************************************
00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved.
00003 * 
00004 * This software is protected by copyright laws of the United States and
00005 * of foreign countries. This material may also be protected by patent laws
00006 * and technology transfer regulations of the United States and of foreign
00007 * countries. This software is furnished under a license agreement and/or a
00008 * nondisclosure agreement and may only be used or reproduced in accordance
00009 * with the terms of those agreements. Dissemination of this information to
00010 * any party or parties not specified in the license agreement and/or
00011 * nondisclosure agreement is expressly prohibited.
00012 *
00013 * The above copyright notice and this permission notice shall be included
00014 * in all copies or substantial portions of the Software.
00015 *
00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00017 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00019 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00020 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00021 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00022 * OTHER DEALINGS IN THE SOFTWARE.
00023 *
00024 * Except as contained in this notice, the name of Maxim Integrated
00025 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00026 * Products, Inc. Branding Policy.
00027 *
00028 * The mere transfer of this software does not imply any licenses
00029 * of trade secrets, proprietary technology, copyrights, patents,
00030 * trademarks, maskwork rights, or any other form of intellectual
00031 * property whatsoever. Maxim Integrated Products, Inc. retains all
00032 * ownership rights.
00033 *******************************************************************************
00034 */
00035 
00036 using System;
00037 using System.Collections;
00038 using System.Collections.Generic;
00039 using System.Linq;
00040 using System.Text;
00041 
00042 //------------------------------------------------------------------------------------------
00043 // OS24EVK-59 split into HeartRateApp EXE and MAX30101 DLL.
00044 // Moved all MAX30101 DLL classes into namespace Maxim.MAX30101GUI
00045 // Moved all HeartRateApp GUI classes into namespace Maxim.MAX30101
00046 // OS24EVK-59 Create separate project that builds Maxim.MAX30101GUI DLL library
00047 
00048 namespace Maxim.MAX30101GUI
00049 {
00050     /// <summary>
00051     /// Encapsulate the Maxim SKA Algorithm
00052     /// </summary>
00053     public class MaximSKAlgorithmClass : MaximAlgorithmClass
00054     {
00055         public MaximSKAlgorithmClass()
00056         {
00057             // https://jira.maxim-ic.com/browse/OS24EVK-40 remove "algorithm" from algorithm names
00058             // https://jira.maxim-ic.com/browse/OS24EVK-45 Rename PBA / SKA algorithms
00059             Name = "Maxim Example Algorithm 2 [SKA.dll]";
00060         }
00061 
00062         // https://jira.maxim-ic.com/browse/OS24EVK-15 any SKA dependencies? e.g. init MaximSKAlgorithmClass._cboPulseWidthIndex from (byte)(cboPulseWidth.SelectedIndex)
00063         // public byte _cboPulseWidthIndex = 0;
00064 
00065         // Steve Koh's variables
00066         int _heartRateBPMint; // alias HR
00067         float _spO2Percentfloat; // alias fSPO2
00068 
00069         const int _SKA_windowSize = 100;
00070         const int _SKA_bufferSize = 500;
00071         // https://jira.maxim-ic.com/browse/OS24EVK-15 MaximSKAlgorithmClass accumulate irBuf[0..] _SKA_bufferSize for SKA.SKA_work
00072         int[] irBuf = new int[_SKA_bufferSize];
00073         int[] redBuf = new int[_SKA_bufferSize];
00074         int[] greenBuf = new int[_SKA_bufferSize];
00075         // https://jira.maxim-ic.com/browse/OS24EVK-35 Support HR from Green LED (SKA)
00076         ArrayList _SKA_IRList = new ArrayList();
00077         ArrayList _SKA_tempIRList = new ArrayList();
00078         ArrayList _SKA_redList = new ArrayList();
00079         ArrayList _SKA_tempRedList = new ArrayList();
00080         ArrayList _SKA_greenList = new ArrayList();
00081         ArrayList _SKA_tempGreenList = new ArrayList();
00082         int _SKA_numSamplesSinceLastCalc;
00083         int _SKA_elapsedSecond;
00084         //int _SKA_validHRcount;
00085         //int _SKA_invalidHRcount;
00086         //int _SKA_validSPO2count;
00087         //int _SKA_invalidSPO2count;
00088         //int _SKA_lastValidHRtimestamp;
00089         //int _SKA_lastValidSPO2timestamp;
00090         // diagnostic: output from SKA algorithm filtering
00091         float[] irAcBuf = new float[100];
00092         float[] redAcBuf = new float[100];
00093         // end of Steve Koh's variables
00094 
00095         /// <summary>
00096         /// Clear any internal class members,
00097         /// in response to startMonitorToolStripMenuItem
00098         /// </summary>
00099         override public void Clear()
00100         {
00101             _SKA_elapsedSecond = 1;
00102             //_SKA_lastValidHRtimestamp = 1;
00103             //_SKA_lastValidSPO2timestamp = 1;
00104             //_SKA_validHRcount = 0;
00105             //_SKA_invalidHRcount = 0;
00106             //_SKA_validSPO2count = 0;
00107             //_SKA_invalidSPO2count = 0;
00108 
00109             _SKA_IRList = new ArrayList();
00110             _SKA_tempIRList = new ArrayList();
00111             _SKA_redList = new ArrayList();
00112             _SKA_tempRedList = new ArrayList();
00113             _SKA_greenList = new ArrayList();
00114             _SKA_tempGreenList = new ArrayList();
00115             _SKA_numSamplesSinceLastCalc = 0;
00116             // https://jira.maxim-ic.com/browse/OS24EVK-15 SKA need preload _SKA_IRList _SKA_bufferSize in startMonitorToolStripMenuItem_Click
00117             for (int index = 0; index < _SKA_bufferSize; index++)
00118             {
00119                 _SKA_IRList.Add(0);
00120                 _SKA_redList.Add(0);
00121                 _SKA_greenList.Add(0);
00122             }
00123         }
00124 
00125         /// <summary>
00126         /// <para>InterfaceRedIRGreenLEDdataConsumer</para>
00127         /// <para>Producer-Consumer data sink for
00128         /// raw Red/IR/Green LED data.
00129         /// Produced by MAX30101, consumed by algorithm.
00130         /// </para>
00131         /// </summary>
00132         /// <param name="sampleNumber"></param>
00133         /// <param name="rawIR"></param>
00134         /// <param name="rawRed"></param>
00135         /// <param name="rawGreen"></param>
00136         /// <param name="rawIRvalid"></param>
00137         /// <param name="rawRedvalid"></param>
00138         /// <param name="rawGreenvalid"></param>
00139         override public void ConsumeRedIRGreenLEDdata(
00140                 int sampleNumber,
00141                 int rawIR,
00142                 int rawRed,
00143                 int rawGreen,
00144                 bool rawIRvalid,
00145                 bool rawRedvalid,
00146                 bool rawGreenvalid
00147             )
00148         {
00149             base.ConsumeRedIRGreenLEDdata(sampleNumber, rawIR, rawRed, rawGreen, rawIRvalid, rawRedvalid, rawGreenvalid);
00150 
00151             bool valid_IR = rawIRvalid;
00152             bool valid_Red = rawRedvalid;
00153             bool valid_Green = rawGreenvalid;
00154             // https://jira.maxim-ic.com/browse/OS24EVK-25 SpO2 mode if LED mode and Red and IR data
00155             bool HRvalid = (valid_Red || valid_Green);
00156             bool SPO2valid = (valid_Red && valid_IR);
00157             //
00158             // example: https://jira.maxim-ic.com/browse/OS24EVK-37 SpO2 Temperature Compensation
00159             #region SpO2_Temperature_Compensation
00160             // SpO2 Temperature Compensation (See MAX30101 data sheet, Applications Information)
00161             // Estimate red LED temperature rise from peak current and pulse width configuration settings,
00162             // then use estimated red LED temperature to estimate actual red LED wavelength.
00163             //
00164             // double red_LED_temperature_delta = lookup table from peak current and duty cycle
00165             // See MAX30101 data sheet Table 13. RED LED Current Settings vs LED Temperature Rise
00166             //
00167             // double red_LED_temperatureDegreesC = base._temperatureDegreesC +  red_LED_temperature_delta;
00168             //
00169             // double red_LED_wavelength = lookup table from red_LED_temperatureDegreesC 
00170             // See MAX30101 data sheet toc10 RED LED PEAK WAVELENGTH vs TEMPERATURE
00171             //
00172             #endregion SpO2_Temperature_Compensation
00173 
00174             double heartRateBPM; // = (double)heartRateBPMint
00175             bool heartRateBPMValid = false;
00176             double heartRateBPMSignalStrength = 0;
00177             double spO2Percent; //  = (double)spO2Percentfloat
00178             bool spO2PercentValid = false;
00179             double spO2PercentSignalStrength = 0; // = (double)SPO2error
00180             float SPO2error = 0;
00181             // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass
00182 
00183             // https://jira.maxim-ic.com/browse/OS24EVK-15 MaximSKAlgorithmClass accumulate irBuf[0..] _SKA_bufferSize for SKA.SKA_work
00184             // int[] irBuf = new int[_SKA_bufferSize];
00185             // int[] redBuf = new int[_SKA_bufferSize];
00186             for (int index = 0; index < _SKA_tempRedList.Count; index++)
00187             {
00188                 _SKA_IRList.Add((int)_SKA_tempIRList[index]);
00189                 _SKA_IRList.RemoveAt(0);
00190                 _SKA_redList.Add((int)_SKA_tempRedList[index]);
00191                 _SKA_redList.RemoveAt(0);
00192                 _SKA_greenList.Add((int)_SKA_tempGreenList[index]);
00193                 _SKA_greenList.RemoveAt(0);
00194                 _SKA_numSamplesSinceLastCalc++;
00195             }
00196             _SKA_tempIRList.Clear();
00197             _SKA_tempRedList.Clear();
00198             _SKA_tempGreenList.Clear();
00199             //
00200             if (_SKA_numSamplesSinceLastCalc < _SKA_windowSize)
00201             {
00202                 _SKA_IRList.Add(rawIR);
00203                 _SKA_IRList.RemoveAt(0);
00204                 _SKA_redList.Add(rawRed);
00205                 _SKA_redList.RemoveAt(0);
00206                 _SKA_greenList.Add(rawGreen);
00207                 _SKA_greenList.RemoveAt(0);
00208             }
00209             else
00210             {
00211                 _SKA_tempIRList.Add(rawIR);
00212                 _SKA_tempRedList.Add(rawRed);
00213                 _SKA_tempGreenList.Add(rawGreen);
00214             }
00215             _SKA_numSamplesSinceLastCalc++;
00216             //
00217             if (_SKA_numSamplesSinceLastCalc >= _SKA_windowSize)
00218             {
00219                 _SKA_numSamplesSinceLastCalc = 0;
00220                 for (int index = 0; index < _SKA_IRList.Count; index++)
00221                 {
00222                     irBuf[index] = (int)_SKA_IRList[index];
00223                     redBuf[index] = (int)_SKA_redList[index];
00224                     greenBuf[index] = (int)_SKA_greenList[index];
00225                 }
00226 
00227                 // Steve Koh's algorithm uses Fs=100Sps. It processes 500 samples at a time. Shift in 100 new samples before the function is called.
00228                 // Since we're running at 100Sps, this routine is called every 100 samples.
00229                 // 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.
00230                 //
00231                 //  Heart Rate/SpO2 Monitor function takes 18bit input irBuffer[500] and redBuffer[500].
00232                 //  Inputs:
00233                 //      int lapsedSecond         -> _SKA_elapsedSecond   must be >3 before anything happens
00234                 //      const int irBuffer[500]  -> irBuf
00235                 //      const int redBuffer[500] -> redBuf
00236                 //  Outputs:
00237                 //      unsigned int *heartRate  -> HR          Heart Rate in beats per minute.
00238                 //      float *SPO2              -> fSPO2       SpO2 value as %saturation.
00239                 //      boolean_T *SPO2valid     -> SPO2valid
00240                 //      boolean_T *HRvalid       -> HRvalid
00241                 //      float *SPO2errorStatus   -> SPO2error   looks like a signal strength?
00242                 //      float last100Ir[100]     -> irAcBuf
00243                 //      float last100Red[100]    -> redAcBuf
00244                 //
00245                 if (valid_Green && !valid_IR) // Green mode - green into IR channel
00246                 {
00247                     // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass
00248                     // https://jira.maxim-ic.com/browse/OS24EVK-35 Support HR from Green LED (SKA Algorithm)
00249                     // for SKA green LED support, looks like we have to preload redBuf with Green LED data...
00250                     // no IR, but we can use Green instead for HR. (No SpO2 measurement so both channels Green.)
00251                     SKA.SKA_work(
00252                         _SKA_elapsedSecond, 
00253                         greenBuf, 
00254                         greenBuf, 
00255                         ref _heartRateBPMint, 
00256                         ref _spO2Percentfloat,
00257                         ref spO2PercentValid,
00258                         ref heartRateBPMValid, 
00259                         ref SPO2error, 
00260                         irAcBuf, 
00261                         redAcBuf);
00262                 }
00263                 else if (valid_Red && !valid_IR && !valid_Green) // HR mode - red into IR channel
00264                 {
00265                     SKA.SKA_work(
00266                         _SKA_elapsedSecond,
00267                         redBuf,
00268                         redBuf,
00269                         ref _heartRateBPMint,
00270                         ref _spO2Percentfloat,
00271                         ref spO2PercentValid,
00272                         ref heartRateBPMValid,
00273                         ref SPO2error,
00274                         irAcBuf,
00275                         redAcBuf);
00276                 }
00277                 else // SpO2 mode
00278                 {
00279                     // https://jira.maxim-ic.com/browse/OS24EVK-15 move SKA algorithm into MaximSKAlgorithmClass
00280                     // normal HR from Red, SpO2 if IR is available
00281                     // SKA.SKA_work(_SKA_elapsedSecond, irBuf, redBuf, ref HR, ref fSPO2, ref SPO2valid, ref HRvalid, ref SPO2error, irAcBuf, redAcBuf);
00282                     SKA.SKA_work(
00283                         _SKA_elapsedSecond, 
00284                         irBuf, 
00285                         redBuf, 
00286                         ref _heartRateBPMint, 
00287                         ref _spO2Percentfloat,
00288                         ref spO2PercentValid,
00289                         ref heartRateBPMValid, 
00290                         ref SPO2error, 
00291                         irAcBuf, 
00292                         redAcBuf);
00293                 }
00294                 _SKA_elapsedSecond++;
00295 
00296 
00297             // https://jira.maxim-ic.com/browse/OS24EVK-15 SKA algorithm report results by InterfaceHeartRateSpO2dataConsumer.ConsumeHeartRateSpO2data(heartRateBPM, ...)
00298             heartRateBPM = (double)_heartRateBPMint;
00299             spO2Percent = (double)_spO2Percentfloat;
00300             // OS24EVK-35 don't report SpO2 if there was not valid red and IR data (i.e. green only)
00301             if (!(valid_Red && valid_IR)) { spO2PercentValid = false; }
00302             spO2PercentSignalStrength = (double)SPO2error;
00303             // https://jira.maxim-ic.com/browse/OS24EVK-15 SKAAlgorithm reporting SpO2 999 as if that was valid.
00304             // SKA Algorithm reports SpO2 bogus value 999% as valid; need to determine why reported as a valid result.
00305             // spO2PercentValid = (spO2PercentSignalStrength > 0);
00306             // don't modify spO2PercentValid; already passed by ref from SKA.SKA_work()
00307             ReportResultsHeartRateSpO2dataAvailable(heartRateBPM, heartRateBPMValid, heartRateBPMSignalStrength, spO2Percent, spO2PercentValid, spO2PercentSignalStrength);
00308             System.Diagnostics.Debug.Print("heartRateBPM: " + heartRateBPM + " heartRateBPMValid: " + heartRateBPMValid + " spO2Percent: " + spO2Percent + " spO2PercentValid: " + spO2PercentValid);
00309             } // if (_SKA_numSamplesSinceLastCalc >= _SKA_windowSize)
00310         }
00311    
00312     }
00313 }