Arduino library for heart rate monitoring with pulse oximeter

Arduino library for heart rate monitoring with pulse oximeter

Arduino library for heart rate monitoring with pulse oximeter

One of the parameters monitored in my sleep management project

It's the pulse. to measure it I developed a device based on the behavior of hemoglobin and oxyhemoglobin against different wavelengths of light. Basically it is about measuring how much light of a certain type is able to pass through or be reflected in a well-irrigated area of ​​the body. The frequency with which a complete cycle of this phenomenon occurs allows measuring the pulse.

Table of Contents

    In the design and testing phase of the pulse measuring device I developed some small programs to help me verify that the assembly was correct. Firstly I wrote the code below, which took the measured values ​​from time to time (at least every MAXIMUM_MEASUREMENT_TIME and at most each MINIMUM_MEASUREMENT_TIME) when they varied a minimum between one and the previous one (the value that corresponds to MINIMUM_SIZE) and the monitored from a computer with a Python application to be able to analyze them later.

    Once the values ​​were adjusted (starting with very dense measurements) I got a collection of values ​​from the pulse oximeter over time that I could graph using a spreadsheet, LibreOffice Calc de LibreOffice, specific.

    graph of pulse oximeter measurements with

    With the data collected, as represented in the image above, the next operation was to determine if the density of values ​​allowed us to calculate in a reliable but "economical" way (not sampling more than the necessary data) the value of the pulse; As can be seen in the graph below, the measures taken seemed to serve to obtain the results that are reasonable to expect.

    .

    measurement of the presence of oxyhemoglobin over time with a pulse oximeter

    Next, with the information from the data sampling, it was necessary to develop an algorithm that would measure the pulse rate. Sticking to the graph that, for simplicity, it is assumed that it represents a layout similar to the QRS complex, the simplest thing seems to be to measure the times between the most prominent parts, with higher values ​​(which corresponds to the qRs zone of depolarization of the ventricles), discarding the flatter and "noisier" zone, which is therefore more difficult to measure. The solution adopted, which corresponds to the test code below, works according to the following procedure:

    • Detect the area that is being measured in each case to only attend to the value peaks qRs and throw away the valley. To do this, values ​​higher than a certain constant could be measured, but there is a risk that an individual and/or circumstances could, although proportionally, raise or lower the values. To avoid this, a value in the area is considered greater than the one that exceeds the average value by a certain coefficient. In this way, the measurement is sensitively self-calibrated and could be adjusted even further by fine-tuning the coefficient, which in my case I have achieved experimentally during the tests.

      Choose the values ​​of the descending zone for the measurement (Rs) of the peak qRs, as close as possible to the maximum of the curve. To know that the ascending zone is being abandoned, it is enough to verify that a new value is less than the previous one and verify that the searched value has not yet been found since, in general, there are several values ​​in the descending zone of qRs depending on the sampling density. To time the pulse, the value of the instant at which the point was found is stored (the milliseconds returned by millis ()) and compares it with the next one.

      To ensure that the value measured is the largest in the descending zone of the highest curve, a variable is used boolean (measure_pulse in this example and active_pulse_measurement in the library) that is activated when entering the ascending zone of the major curve and deactivated once the first descending value is found, which is the timed one.

      As it is usual to represent the duration of the pulse as beats per minute (ppm), the value of time between pulses obtained is corrected by calculating by dividing the total time of the representation (one minute, 60000 milliseconds) by the interval obtained by subtracting the current milliseconds ( of the current value) among those previously timed.

      To avoid false measurements (such as the device measuring in a vacuum, for example), it is verified that the result is between maximum and minimum values ​​before taking it for granted. Although it is considered as an average that a normal value for a healthy adult at rest is between 60 and 100 ppm, there are admissible values ​​below, it is easy to find 40 ppm in an athlete at rest, up to 200 ppm during intense exercise and more. of 100 ppm in sedentary adults in states of excitement, precisely an interesting factor for the sleep management project which leads me to develop this pulse measuring device. For this reason, it is advisable to relax these values ​​a lot so that the extremes are not lost, which could precisely show relevant aspects.

      The new average value is calculated by decreasing the relevance of the current average based on the number of values ​​sampled and the last value is added, also weighted with a coefficient that reduces it further the more values ​​that have been measured so far.

    Finally, using the algorithm described before, I developed the library to calculate the pulse by detecting the presence of the hemoglobin or the oxyhemoglobin (depending on the wavelength of light used) from the code below.

    The library expects the sampling function to be called periodically monitor_pulse() to calculate the pulse, which can be consulted with the function last_pulse() or with the function average_pulse() the average pulse. In addition to being a limited resource, I ruled out using interruptions because I did not need immediate values ​​but rather sustained ones over time to monitor the pulse in my sleep management project

    . In any case, from the tests I have done, it does not seem to be necessary; either by the device or by the behavior of the pulse, sampling at a certain frequency offers enough information and not much more (relevant) is obtained by increasing it, nor is it possible to decrease it much without losing relevant data for the calculation; in early versions of the code to monitor the reading of the pulse oximeter I discovered that it was not necessary to stick to a maximum measurement time since, if the variations of successive values ​​were correctly considered, it was very close to the minimum.

    The following example program shows how to use the previous library to measure the pulse with pulse oximeter. In addition to instantiating the class Pulse monitoring of the level of oxyhemoglobin/hemoglobin and with a smaller periodicity the value of the pulse calculated and average.

    To ensure that the measurements are relevant, a wait is programmed before displaying any value. As the value may be incorrect (for example if the user removes the device), values ​​are only shown if they are within the range of those considered valid.

    Post Comment

    You May Have Missed