For a recent project I was asked if I can build a device to measure the pulse rate of a person. Sure.
There is this great Pulse Sensor Project which already developed a pulse sensor for Arduino. Hooking this up to Arduino and you are done.
Don‘t get me wrong the Pulse Sensor sensor is really good but it was just not fitting for our purposes:
- We needed to measure the pulse at the tip of a finger. There was no way to attach a clip to the earlobe or so. And the Pulse Sensor sensor had real issues if the lightning of the measured object (i.e. the finger or earlobe) is not perfect.
- The customer really did not like the idea of using visible light for measurement. He wanted to make it appear more magically. Hence it was obvious that infrared light had to be used for illumination.
- It needed to work (at least virtually) every time. No matter which person used the device it had to work reasonable well.
Fortunately the Pulse Sensor guys started with an infrared version of their pulse sensor and had a great in-depth documentation on their blog. So everything needed was a nice set of IR LEDs and a fitting IR sensor. So starting with the sensor: It had to be flat, finger compatible and – uhm that is pretty much all. So how about a the OSRAM BP 104 – they come in a large variety of wavelength and mounting options and are flat and really big – ideally suited to be put under a finger and they block visible light – so we had not to deal with influences by visible light, which is more common than strong infrared signals.
But which IR LED to use. Of course it should be matched in wavelength. And with a flat finger sensor it was clear that a right angle illumination through the finger would be ideal. The TSKS5400S seemed quite fitting. So, using three IR LEDs on each side of the finger seemed to be quite a robust solution (the fourht side of the finger is obviously attached to the hand).
Not really centred on the bread board – but you get the idea. Reading out the IR diode was also quite straight forward. The solution to use an opamp with a feedback resistor. The specific resistor value is extremely sensible to illumination, sensor, finger position and so on. So a potentiometer was a reasonable solution.
Wrong! The potentiometer had a reasonable drift and the noise of the long wires made it quite unusable – so I used the excellent AD5241 digital resistors, which are set over I2C by the Arduino. A simple and elegant solution. The readout logic in the end looked like this:
The infrared light induces a reverse current in the IR diode just like a very small solar panel. The opamp is used to convert the current into a voltage. The positive input is connected to ground so that the opamp tries to tie the negative input to ground too by the feedback network. But current through the IR diode ties the negative input to a lower voltage. This is equalised by the feedback resistor – in this schematic a bit awkward looking because it is a digital potentiometer. By these electric forces – the opamp trying to keep the negative input at 0V and the IR diode inducing a current flowing trough the feedback resistor we get a nice voltage at the output of the opamp, determined by U=R*I. The output voltage is the product of the current through the IR diode and the resistance of the feedback resistor. Pretty complicated but once you understood it very easy and best of all quite precise.
But choosing the right opamp for this task was not easy. The garden variety LM358 lead to exactly no result. It was nerve-wracking. But after some analysation it was clear. We need an opamp with extremely low input bias current on the negative input – since we are measuring an extremely small current. A small input bias voltage is nice too. The Burr Brown OPA347 seemed to do the trick and was not too expensive (really a nice opamp).
The result was a bit underwhelming:
As you can see I have used more or less the original Pulse Sensor Arduino Sketch and Client Software (Version 05). There is a digital low pass filter smoothing the signal. In the above picture you see me putting the finger on the sensor. I do not know how the software was able to detect a pulse – but as you can see from the graphics there is at best a small hint of the pulse. Nothing to get a proper and robust readout.
Filter the pulse to success
First of all we have to get rid of all the high frequency signals with a simple low pass filter with a corner frequency of 75Hz to smoothen out the readout and not confusing our simple pulse detection algorithm with unnecessary noise.
Much better. As you can see there seems to be a small pulse present. But that is not nearly enough to get a proper readout. We needed to have a much stronger signal. But before we can amplify this signal we have to get rid of the DC part of the signal. Because the actual light level was only mildly interesting – in the end it was used to determine if there is a finger on the sensor or not. We only want to know the pulse which is a relative signal in the output somewhere between 2Hz and 25Hz. So we needed a high pass filter to get the relative signal. This can be later amplified by another opamp. If we amplify the absolute signal of 3V by factor 100 we end up with readings in the 300V region – very impractical.
The values given in the schematics give a nice 2,34Hz high pass filter – low enough to retain the low-frequency parts of the pulse and high enough to remove the DC component relatively fast. To be really on the safe side another 11Hz low pass filter was added to further smooth the signal.
As you can see from the schematic the reference point for the second signal was VCC/2 – i.e. 2.5V – instead of GND. This made the signal oscillate around 2.5V – a very nice trick to keep the signal in the Arduino measurement range. In the final version the very nice TLE2426 rail splitter was used, an extremely useful device just for the purpose to give you a precise and fast VCC/2 – but for bread boarding two simple resistors were enough, since I got no TLE2426 at hand.
As you can see from the bread boarding we are getting close to real proper analogue circuitry. And the result did not come very short of the expectations:
It is the same situation as above: I put my finger on the sensor to detect a pulse. As you can see we only get the relative signal and removed a good amount of the noise. The peaks are the artefacts of the steep signal changes when I put my finger on the sensor. And after the peaks you see some very small glimpse of the pulse.
Crank it to the max
But this pulse signal is still far from usable. Of course with some extremely well done programming you could detect the pulse in this signal. but it is much easier to use an opamp to amplify the signal in the analogue domain.
Again the schematic is extremely simple (if not over simplified). Another digital potentiometer in the feedback loop of the second opamp simply selects the gain. In this case it was around 40 before the opamp got unstable. The reference for the opamp was VCC/2 and not GND – since we wanted to amplify the difference of the signal to VCC/2 and not the signal itself. By that VCC/2 is our virtual ground.
It would have been nice to use a different schematic with a fixed value resistor between the VCC/2 and the negative input – giving a far more stable solution to get a higher gain. But since the final gain was unclear to me I used the above solution – not a good idea, but workable in our case.
The resulting analogue circuitry was far from easy.
You can clearly see that we read out the absolute signal to detect if there is a finger on the sensor and the relative signal to detect the pulse.
After all this analogue trickery the result was quite impressive.
There is still some noise in the signal but what you see in the right half of the diagram is a proper and clean pulse signal. Most of the imprecision and noise is to blame the fact that this whole experiment was done on bread board with really long wires (for the complex task). After redoing the circuit on on perfboard it got way better and on the final PCB it was excellent. The absolute signal helped a lot to filter out a lot of the noise if no finger was present – simply by ignoring it.
In the end the solution worked far better than the original Pulse Sensor sensor. Which is no surprise because I used much more effort in the analogue domain – giving me some additional grey hairs. But it worked in nearly all cases. It was quite robust to finger placement and the individual person owning the finger (with the Pulse Sensor sensor one person in the team was never able to get a proper readout – so this person was our litmus test)
The analogue filter design is essential for a proper pulse readout. There are still some things to improve on this part. A real big improvement can be achieved by using active filters of a higher order to obtain a much sharper filter response, really leaving only the frequencies between about 1Hz and 20Hz. I played around with that but with very mixed results. I integrated the high gain into an Sallen Key filter – which is an excellent way to implement oscillation circuits but of course only lead to frustration on my side. But I still think this is the way to go – unfortunately I did not have enough time to test this.
The illumination of the finger is also very critical. The three IR diode method was a bit over engineered but still far from perfect. A lot of light was conducted by the surface of the finger – perhaps an illumination through the finger would have been better – unfortunately it was not physically achievable in the project. But medical devices can even measure the amount of oxygen in the blood by similar solutions – so there is still a lot to explore …