In this article, we will introduce a method to calculate heart rate using the analog signal output from a pulse sensor. This method has been tested and the resulting heart rate values are quite accurate, with high measurement efficiency. First, let’s introduce the pulse sensor used in this article.
This sensor measures the intensity of the pulse and outputs an analog signal. It uses the “photoplethysmography” method to measure the pulse. Below is a description of the principle extracted from the module manual: “Photoplethysmography measures the pulse by utilizing the difference in light transmittance caused by blood vessel pulsations in human tissue. The light source is a light-emitting diode with a specific wavelength (500NM-700NM) that selectively targets oxygen and hemoglobin in arterial blood. When the light beam passes through peripheral blood vessels, the change in blood volume caused by arterial pulsation leads to a change in light transmittance. At this point, a phototransducer receives the reflected and varying light signal from the human tissue and converts it into an output voltage signal.” This sensor only requires contact with a fingertip or being clipped onto the earlobe to measure, but the downside is that measurement may fail if the skin is wet or the contact with the sensor is insufficient.
Next, we will use Arduino to collect the raw data from the sensor and output the raw data to the Arduino IDE’s serial plotter to observe the “electrocardiogram”. (The code is relatively simple; just start the serial port and then “print” the AD sampled values.) The following figure shows the curve obtained when the sensor has good contact with the fingertip, with a sampling period of 10 milliseconds:
Next, let’s take a look at the curve obtained when the fingertip is not in contact with the sensor:
From the above two figures, we can see that when the sensor collects the pulse, it outputs a “pulsating” signal corresponding to the heartbeat, with a maximum value around 800 and a minimum value around 400. We can see the specific values through the serial monitor. These two values vary from person to person, and different individuals will obtain different peak and valley values. When the fingertip is removed, the sensor is “suspended”, resulting in the curve shown in the second figure, where the data will fluctuate slightly between 500-600. Thus, we have a basic understanding of the output signal of the sensor, but the key of this article is not to look at this “electrocardiogram”. Although the system collects and prints the data, it does not know the heart rate—how many heartbeats are in the collected “electrocardiogram”. Therefore, the next key is to design a processing method to obtain the number of heartbeats from the “electrocardiogram”.
When I first encountered this sensor, I thought it would be simple to calculate the heart rate: just count how many peaks occurred in one minute to know the heart rate. However, in reality, this method does not work; it has two problems: 1, how to count the “peaks”; 2, measuring heart rate once requires continuous sampling of signals for more than one minute, which is too inefficient. After reviewing the data and careful consideration, I established a calculation idea: measure the time interval between two “peaks”, and then infer the heart rate per minute. However, there is still one problem: how to identify a “peak”? From the waveform, we can easily think of setting a “threshold”; when the value exceeds that threshold, it is recorded as a peak. However, what is the appropriate threshold for the peak? Different people, or the same person at different times or states, will yield inconsistent peak values. This method is still not feasible. From the above figures, we can see that each peak’s peak value is actually inconsistent; one peak is significantly lower than the others. If we simply set a threshold, it may lead to significant errors in calculating the heart rate. So, how can we accurately determine a peak?
By observing the waveform, we can conclude: a peak must undergo a “monotonically increasing” and a “monotonically decreasing” process. Therefore, after sampling data once, we can immediately perform a “derivative” on the “curve”, which means calculating the slope of the curve. We can obtain a “derivative” by subtracting the last sampled value from the current sampled value. In the monotonically increasing interval, the derivative is positive; in the monotonically decreasing interval, the derivative is negative; at the peak, there must be a point where the derivative equals zero. In fact, the point where the derivative equals 0 is the best point for us to perform timing calculations, but this point is very difficult to sample. Therefore, we can only take the moment when the derivative first changes from positive to negative as the timing start and calculation feature point. Additionally, in the “electrocardiogram”, we can also see that beside the “big peak”, there is also a “small peak”. The small peak undergoes the same change process in its derivative, but this small peak does not contribute to heart rate calculations. However, if we do not process it, it will have a huge impact on heart rate calculations. To “remove” the small peak, we can record the maximum and minimum values of the curve during sampling. When the system detects the derivative as negative, we can reference whether the current sampled value is less than the maximum value and greater than the minimum value plus a certain value, thus isolating the influence of the small peak.
The theorem in the figure below illustrates the relationship between the monotonicity of a function and its derivative:
Based on the above method, in the first experiment, I directly introduced the AD sampled values for calculation, and the result was a failure. The reason for the failure is that the “derivative” kept switching between positive and negative. Further analysis of the “electrocardiogram” revealed that this was caused by the “spikes” in the “electrocardiogram”. Therefore, before performing derivative calculations, we should also filter the AD sampled values. With previous experience in processing gyroscope and accelerometer data, we can use a first-order lag filter method here, which essentially means that the current output value is a weighted sum of the last output value and the current measurement value. Let’s take a look at the filtered electrocardiogram, with a sampling period of 10 milliseconds:
From the above figure, we can see that the “electrocardiogram” after filtering has become much smoother, the “spikes” have disappeared, and the “small peaks” have also been significantly flattened, which greatly benefits heart rate calculations. Below is the code for printing the basic “electrocardiogram” and the code for outputting heart rate calculations:
Below is the output display of the heart rate measurement calculation:
In the above code, the LED on pin 13 synchronously indicates the heartbeat—i.e., the LED flashes with each heartbeat. During the measurement process, if the system detects that the “derivative” remains within the range of positive and negative 5 (this range can be determined by outputting the derivative values through the serial port) or if the AD sampled filtered value is below the maximum peak value minus 200, counting will begin. If this condition is met continuously for two seconds, the system will determine that the fingertip has been removed or that there is no heartbeat, at which point the maximum and minimum values of the curve will be reset.
Below is a demonstration video:
Welcome to follow the Intelligent DIY Maker Space, where we will successively share the learning process of Freescale, STM32, and more fun projects with Arduino. We are dedicated to research on maker courses and project development practice. The summer youth maker activity course continues!
Address: Room 305, Business Building, No. 50 Hongta Avenue, Hongta District, Yuxi City, Intelligent DIY Maker Space
Phone: 13577781795