Posts with «pulse» label

Simple and Inexpensive Heartbeat Detector

There are many ways to detect a heartbeat electronically. One of the simpler ways is to take [Orlando’s] approach. He’s built a finger-mounted pulse detector using a few simple components and an Arduino.

This circuit uses a method known as photoplethysmography. As blood is pumped through your body, the volume of blood in your extremities increases and decreases with each heartbeat. This method uses a light source and a detector to determine changes in the amount of blood in your extremities. In this case, [Orlando] is using the finger.

[Orlando] built a finger cuff containing an infrared LED and a photodiode. These components reside on opposite sides of the finger. The IR LED shines light through the finger while the photodiode detects it on the other side. The photodiode detects changes in the amount of light as blood pumps in and out of the finger.

The sensor is hooked up to an op amp circuit in order to convert the varying current into a varying voltage. The signal is then filtered and amplified. An Arduino detects the voltage changes and transmits the information to a computer via serial. [Orlando] has written both a LabVIEW program as well as a Processing program to plot the data as a waveform. If you’d rather ditch the PC altogether, you might want to check out this standalone heartbeat sensor instead.


Filed under: Arduino Hacks

Medical Tricorder Mark I

A handheld tricorder is as good a reason as any to start a project. The science-fiction-derived form factor provides an opportunity to work on a lot of different areas of hardware development like portable power, charging, communications between sensor and microcontroller. And of course you need a user interface so that the values being returned will have some meaning for the user.

[Marcus B] has done a great job with all of this in his first version of a medical tricorder. The current design hosts two sensors, one measures skin temperature using infrared, the other is a pulse sensor.

For us it’s not the number of sensors that makes something a “tricorder” but the ability of the device to use those sensors to make a diagnosis (or to give the user enough hints to come to their own conclusion). [Marcus] shares similar views and with that in mind has designed in a real-time clock and an SD card slot. These can be used to log sensor data over time which may then be able to suggest ailments based on a known set of common diagnosis parameters.

Looking at the image above you may be wondering which chip is the microcontroller. This build is actually a shield for an Arduino hiding underneath.

There’s a demonstration video after the break. And if you find this impressive you won’t want to miss the Open Source Science Tricorder which is one of the finalists for the 2014 Hackaday Prize.

 


Filed under: Medical hacks
Hack a Day 08 Nov 03:01

Failed attempt at pulse oximeter

In Optical pulse monitor with little electronics  and Digital filters for pulse monitor, I developed an optical pulse monitor using an IR emitter, a phototransistor, 2 resistors, and an Arduino.  On Thursday, I decided to try to extend this to a pulse oximeter, by adding a red LED (and current-limiting resistor) as well.  Because excluding ambient light is so important, I decided to build a mount for everything out of a block of wood:

Short piece of 2×2 wood, with a 3/4″ diameter hole drilled with a Forstner bit partway through the block. Two 1/8″ holes drilled for 3mm LEDs on top, and one for a 3mm phototransistor on the bottom (lined up with the red LED). Wiring channels were cut with the same 1/8″ drill bit, and opened up a with a round riffler. Electrical tape holds the LEDs and phototransistor in place (removed here to expose the diodes).

My first test with the new setup was disappointing.  The signal from the IR LED swamped out the signal from the red LED, being at least 4 times as large. The RC discharge curves for the phototransistor for the IR signal was slow enough that I would have had to go to a very low sampling rate to see the red LED signal without interference from the discharge from the IR pulse.  I could reduce the signal for the IR LED to only twice the red output by increasing the IR current-limiting resistor to 1.5kΩ, and reduce the RC time constant of the phototransistor by reducing the pulldown resistor for it to 100kΩ The reduction in the output of the IR LED and decreased sensitivity of the phototransistor made about a 17-fold reduction in the amplitude of the IR signal, and the red signal was about a thirtieth of what I’d previously been getting for the IR signal.  Since the variation in amplitude that made up my real signal was about 10 counts before, it is substantially less than 1 count now, and is  too small to be detected even with the digital filters that I used.

I could probably solve this problem of a small signal by switching from the Arduino to the KL25Z, since going from a 10-bit ADC to a 16-bit ADC would allow a 64 times larger signal-to-noise ratio (that is, +36dB), getting me back to enough signal to be detectable even with the reductions..  I’ve ordered headers from Digi-Key for the KL25Z, so next week I’ll be able to test this.

I did do something very stupid yesterday, though in a misguided attempt to fix the problem.  I had another red LED (WP710A10ID) that was listed on the spec sheet as being much brighter than the one I’d been using (WP3A8HD), so I soldered it in.  The LED was clearly much brighter, but when I put my finger in the sensor, I got almost no red signal!  What went wrong?

A moment’s thought explained the problem to me (I just wish I had done that thinking BEFORE soldering in the LED).  Why was the new LED brighter for the same current?  It wasn’t that the LED was more efficient at generating photons, but that the wavelength of the light was shorter, and so the eye was more sensitive to it.

Spectrum of the WP3A8HD red LED that I first used. It has a peak at 700nm and dominant wavelength at 660nm. I believe that the “dominant wavelength” refers to the peak of the spectrum multiplied by the sensitivity of the human eye.  Spectrum copied from Kingbright preliminary specification for WP3A8HD.

Spectrum of the WP710A10ID brighter red LED that didn’t work for me. The peak is at 627nm and the “dominant wavelength” is 617nm. The extra brightness is coming from this shorter wavelength, where the human eye is more sensitive. Image copied from the Kingbright spec sheet.

1931 CIE luminosity curve, representing a standardized sensitivity of the human eye with bright lighting (photopic vision). The peak is at 555nm. Note that there are better estimates of human eye sensitivity now available (see the discussion of newer ones in the Wikipedia article on the Luminosity function).
Image copied from Wikipedia.

The new LED is brighter, because the human eye is more sensitive to its shorter wavelength, but the optimum sensitivity of the phototransistor is at longer wavelengths, so the phototransistor is less sensitive to the new LED than to the old one.

Typical spectral sensitivity of a silicon photodiode or phototransistor. This curve does not take into account any absorption losses in the packaging of the part, which can substantially change the response. Note that the peak sensitivity is in the infrared, around 950nm, not in the green around 555nm as with the human eye. Unfortunately, Kingbright does not publish a spectral sensitivity curve for their WP3DP3B phototransistor, so this image is a generic one copied from https://upload.wikimedia.org/wikipedia/commons/4/41/Response_silicon_photodiode.svg

This sensitivity is much better matched to the IR emitter (WP710A10F3C) than to either of the red LEDs:

Spectrum for the WP710A10F3C IR emitter, copied from the Kingbright spec sheet. The peak is at 940nm with a 50nm bandwidth. There is no “dominant wavelength”, because essentially all the emissions are outside the range of the human eye.

Furthermore, blood and flesh is more opaque at the shorter wavelength, so I had more light absorbed and less sensitivity in the detector, making for a much smaller signal.

Scott Prahl’s estimate of oxyhemoglobin and deoxyhemoglobin molar extinction coefficients, copied from http://omlc.ogi.edu/spectra/hemoglobin/summary.gif
Tabulated values are available at http://omlc.ogi.edu/spectra/hemoglobin/summary.html and general discussion at http://omlc.ogi.edu/spectra/hemoglobin/
The higher the curve here the less light is transmitted. Note that 700nm has very low absorption (290), but 627nm has over twice as high an absorption (683).  Also notice that in the infrared

I had to go back to the red LED (WP3A8HD) that I started with. Here is an example of the waveform I get with that LED, dropping the sampling rate to 10Hz:

The green waveform is the voltage driving the red LED and through a 100Ω resistor. The red LED is on for the 1/30th of second that the output is low, then the IR LED is on (through a 1.5kΩ resistor) for 1/30th of a second, then both are off. THe yellow trace shows the voltage at the phototransistor emitter with a 680kΩ pulldown.
This signal seems to have too little amplitude for the variation to be detected with the Arduino (the scale is 1v/division with 0v at the bottom of the grid).

I can try increasing the signal by using 2 or more red LEDs (though the amount of current needed gets large), or I could turn down the IR signal to match the red signal and use an amplifier to get a big enough signal for the Arduino to read.  Sometimes it seems like a 4.7kΩ resistor on the IR emitter matches the output, and sometimes there is still much more IR signal received, depending on which finger I use and how I hold it in the device.

I was thinking of playing with some amplification, but I could only get a gain of about 8, and even then I’d be risking saturation of the amplifier.  I think I’ll wait until the headers come and I can try the KL25Z board—the gain of 64 from the higher resolution ADC is likely to be more useful.  If that isn’t enough, I can try adding gain also.  I could also eliminate the “off-state” and just amplify the difference between IR illumination and red illumination.  I wonder if that will let me detect the pulse, though.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, biquad filter, digital filter, IIR filter, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Failed attempt at pulse oximeter

In Optical pulse monitor with little electronics  and Digital filters for pulse monitor, I developed an optical pulse monitor using an IR emitter, a phototransistor, 2 resistors, and an Arduino.  On Thursday, I decided to try to extend this to a pulse oximeter, by adding a red LED (and current-limiting resistor) as well.  Because excluding ambient light is so important, I decided to build a mount for everything out of a block of wood:

Short piece of 2×2 wood, with a 3/4″ diameter hole drilled with a Forstner bit partway through the block. Two 1/8″ holes drilled for 3mm LEDs on top, and one for a 3mm phototransistor on the bottom (lined up with the red LED). Wiring channels were cut with the same 1/8″ drill bit, and opened up a with a round riffler. Electrical tape holds the LEDs and phototransistor in place (removed here to expose the diodes).

My first test with the new setup was disappointing.  The signal from the IR LED swamped out the signal from the red LED, being at least 4 times as large. The RC discharge curves for the phototransistor for the IR signal was slow enough that I would have had to go to a very low sampling rate to see the red LED signal without interference from the discharge from the IR pulse.  I could reduce the signal for the IR LED to only twice the red output by increasing the IR current-limiting resistor to 1.5kΩ, and reduce the RC time constant of the phototransistor by reducing the pulldown resistor for it to 100kΩ The reduction in the output of the IR LED and decreased sensitivity of the phototransistor made about a 17-fold reduction in the amplitude of the IR signal, and the red signal was about a thirtieth of what I’d previously been getting for the IR signal.  Since the variation in amplitude that made up my real signal was about 10 counts before, it is substantially less than 1 count now, and is  too small to be detected even with the digital filters that I used.

I could probably solve this problem of a small signal by switching from the Arduino to the KL25Z, since going from a 10-bit ADC to a 16-bit ADC would allow a 64 times larger signal-to-noise ratio (that is, +36dB), getting me back to enough signal to be detectable even with the reductions..  I’ve ordered headers from Digi-Key for the KL25Z, so next week I’ll be able to test this.

I did do something very stupid yesterday, though in a misguided attempt to fix the problem.  I had another red LED (WP710A10ID) that was listed on the spec sheet as being much brighter than the one I’d been using (WP3A8HD), so I soldered it in.  The LED was clearly much brighter, but when I put my finger in the sensor, I got almost no red signal!  What went wrong?

A moment’s thought explained the problem to me (I just wish I had done that thinking BEFORE soldering in the LED).  Why was the new LED brighter for the same current?  It wasn’t that the LED was more efficient at generating photons, but that the wavelength of the light was shorter, and so the eye was more sensitive to it.

Spectrum of the WP3A8HD red LED that I first used. It has a peak at 700nm and dominant wavelength at 660nm. I believe that the “dominant wavelength” refers to the peak of the spectrum multiplied by the sensitivity of the human eye.  Spectrum copied from Kingbright preliminary specification for WP3A8HD.

Spectrum of the WP710A10ID brighter red LED that didn’t work for me. The peak is at 627nm and the “dominant wavelength” is 617nm. The extra brightness is coming from this shorter wavelength, where the human eye is more sensitive. Image copied from the Kingbright spec sheet.

1931 CIE luminosity curve, representing a standardized sensitivity of the human eye with bright lighting (photopic vision). The peak is at 555nm. Note that there are better estimates of human eye sensitivity now available (see the discussion of newer ones in the Wikipedia article on the Luminosity function).
Image copied from Wikipedia.

The new LED is brighter, because the human eye is more sensitive to its shorter wavelength, but the optimum sensitivity of the phototransistor is at longer wavelengths, so the phototransistor is less sensitive to the new LED than to the old one.

Typical spectral sensitivity of a silicon photodiode or phototransistor. This curve does not take into account any absorption losses in the packaging of the part, which can substantially change the response. Note that the peak sensitivity is in the infrared, around 950nm, not in the green around 555nm as with the human eye. Unfortunately, Kingbright does not publish a spectral sensitivity curve for their WP3DP3B phototransistor, so this image is a generic one copied from https://upload.wikimedia.org/wikipedia/commons/4/41/Response_silicon_photodiode.svg

This sensitivity is much better matched to the IR emitter (WP710A10F3C) than to either of the red LEDs:

Spectrum for the WP710A10F3C IR emitter, copied from the Kingbright spec sheet. The peak is at 940nm with a 50nm bandwidth. There is no “dominant wavelength”, because essentially all the emissions are outside the range of the human eye.

Furthermore, blood and flesh is more opaque at the shorter wavelength, so I had more light absorbed and less sensitivity in the detector, making for a much smaller signal.

Scott Prahl’s estimate of oxyhemoglobin and deoxyhemoglobin molar extinction coefficients, copied from http://omlc.ogi.edu/spectra/hemoglobin/summary.gif
Tabulated values are available at http://omlc.ogi.edu/spectra/hemoglobin/summary.html and general discussion at http://omlc.ogi.edu/spectra/hemoglobin/
The higher the curve here the less light is transmitted. Note that 700nm has very low absorption (290), but 627nm has over twice as high an absorption (683).  Also notice that in the infrared

I had to go back to the red LED (WP3A8HD) that I started with. Here is an example of the waveform I get with that LED, dropping the sampling rate to 10Hz:

The green waveform is the voltage driving the red LED and through a 100Ω resistor. The red LED is on for the 1/30th of second that the output is low, then the IR LED is on (through a 1.5kΩ resistor) for 1/30th of a second, then both are off. THe yellow trace shows the voltage at the phototransistor emitter with a 680kΩ pulldown.
This signal seems to have too little amplitude for the variation to be detected with the Arduino (the scale is 1v/division with 0v at the bottom of the grid).

I can try increasing the signal by using 2 or more red LEDs (though the amount of current needed gets large), or I could turn down the IR signal to match the red signal and use an amplifier to get a big enough signal for the Arduino to read.  Sometimes it seems like a 4.7kΩ resistor on the IR emitter matches the output, and sometimes there is still much more IR signal received, depending on which finger I use and how I hold it in the device.

I was thinking of playing with some amplification, but I could only get a gain of about 8, and even then I’d be risking saturation of the amplifier.  I think I’ll wait until the headers come and I can try the KL25Z board—the gain of 64 from the higher resolution ADC is likely to be more useful.  If that isn’t enough, I can try adding gain also.  I could also eliminate the “off-state” and just amplify the difference between IR illumination and red illumination.  I wonder if that will let me detect the pulse, though.


Filed under: Circuits course, freshman design seminar Tagged: Arduino, biquad filter, digital filter, IIR filter, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Digital filters for pulse monitor

In Optical pulse monitor with little electronics, I talked a bit about an optical pulse monitor using the Arduino and just 4 components (2 resistors, an IR emitter, and a phototransistor).  Yesterday, I had gotten as far as getting good values for resistors, doing synchronous decoding, and using a very simple low-pass IIR filter to clean up the noise.  The final result still had problems with the baseline shifting (probably due to slight movements of my finger in the sensor):

(click to embiggen) Yesterday’s plot with digital low-pass filtering, using y(t) = (x(t) + 7 y(t-1) )/8.  There is not much noise, but the baseline wobbles up and down a lot, making the signal hard to process automatically.

Today I decided to brush off my digital filter knowledge, which I haven’t used much lately, and see if I could design a filter using only small integer arithmetic on the Arduino, to clean up the signal more. I decided to use a sampling rate fs = 30Hz on the Arduino, to avoid getting any beating due to 60Hz pickup (not that I’ve seen much with my current setup). The 30Hz choice was made because I do two measurements (IR on and IR off) for each sample, so my actual measurements are at 60Hz, and should be in the same place in any noise waveform that is picked up. (Europeans with 50Hz line frequency would want to use 25Hz as their sampling frequency.)

With the 680kΩ resistor that I selected yesterday, the 30Hz sampling leaves plenty of time for the signal to charge and discharge:

The grid line in the center is at 3v. The green trace is the signal to on the positive side of the IR LED, so the LED is on when the trace is low (with 32mA current through the pullup resistor). The yellow trace is the voltage at the Arduino input pin: high when light is visible, low when it is dark. This recording was made with my middle finger between the LED and the phototransistor.

I decided I wanted to replace the low-pass filter with a passband filter, centered near 1Hz (60 beats per minute), but with a range of about 0.4Hz (24 bpm) to 4Hz (240bpm). I don’t need the passband to be particularly flat, so I decided to go with a simple 2-pole, 2-zero filter (called a biquad filter). This filter has the transfer function

To get the gain of the filter at a frequency f, you just compute , where .  Note that the z values that correspond to sinusoids are along the unit circle, from DC at up to the Nyquist frequency at .

The filter is implemented as a simple recurrence relation between the input x and the output y:

This is known as the “direct” implementation.  It takes a bit more memory than the “canonical” implementation, but has some nice properties when used with small-word arithmetic—the intermediate values never get any further from 0 than the output and input values, so there is no overflow to worry about in intermediate computations.

I tried using an online web tool to design the filter http://www-users.cs.york.ac.uk/~fisher/mkfilter/, and I got some results but not everything on the page is working.  One can’t very well complain to Tony Fisher about the maintenance, since he died in 2000. I tried using the tool at http://digitalfilter.com/enindex.html to look at filter gain, but it has an awkward x-axis (linear instead of logarithmic frequency) and was a bit annoying to use.  So I looked at results from Tony Fisher’s program, then used my own gnuplot script to look at the response for filter parameters I was interested in.

The filter program gave me one obvious result (that I should not have needed a program to realize): the two zeros need to be at DC and the Nyquist frequency—that is at ±1.  That means that the numerator of the transfer function is just , and b0=1, b1=0, and b2=–1.  The other two parameters it gave me were a2=0.4327386423 and a1=–1.3802466192.  Of course, I don’t want to use floating-point arithmetic, but small integer arithmetic, so that the only division I do is by powers of 2 (which the compiler turns into a quick shift operation).

I somewhat arbitrarily selected 32 as my power of 2 to divide by, so that my transfer function is now

and my recurrence relation is

with A1 and A2 restricted to be integers.  Rounding the numbers from Fisher’s program suggested A1=-44 and A2=14, but that centered the filter at a bit higher frequency than I liked, so I tweaked the parameters and drew plots to see what the gain function looked like.  I made one serious mistake initially—I neglected to check that the two poles were both inside the unit circle (they were real-valued poles, so the check was just applying the quadratic formula).  My first design (not the one from Fisher’s program) had one pole outside the unit circle—it looked fine on the plot, but when I implemented it, the values grew until the word size was exceeded, then oscillated all over the place.  When I realized what was wrong, I checked the stability criterion and changed the A2 value to make the pole be inside the unit circle.

I eventually ended up with A1=-48 and A2=17, which centered the filter at 1, but did not have as high an upper frequency as I had originally thought I wanted:

(click to embiggen) The gain of the filter that I ended up implementing has -3dB points at about 0.43 and 2.15 Hz.

Here is the gnuplot script I used to generate the plot—it is not fully automatic (the xtics, for example, are manually set). Click it to expand.

fs = 30	# sampling frequency
A0=32.  # multiplier (use power of 2)
b=16.

A1=-(A0+b)
A2=b+1

peak = fs/A0	# approx frequency of peak of filter

set title sprintf("Design of biquad filter, fs=%3g Hz",fs)

set key bottom center
set ylabel "gain [dB]"
unset logscale y
set yrange [-20:30]

set xlabel "frequency [Hz]"
set logscale x
set xrange [0.01:0.5*fs]

set xtics add (0.43, 2.15)
set grid xtics

j=sqrt(-1)
biquad(zinv,b0,b1,b2,a0,a1,a2) = (b0+zinv*(b1+zinv*b2))/(a0+zinv*(a1+zinv*a2))
gain(f,b0,b1,b2,a0,a1,a2) = abs( biquad(exp(j*2*pi*f/fs),b0,b1,b2,a0,a1,a2))
phase(f,b0,b1,b2,a0,a1,a2) = imag(log( biquad(exp(j*2*pi*f/fs),b0,b1,b2,a0,a1,a2)))

plot 20*log(gain(x,A0,0,-A0,  A0,A1,A2)) \
		title sprintf("%.0f (1-z^-2)/(%.0f+ %.0f z^-1 + %.0f z^-2)", \
			A0, A0, A1, A2), \
	20*log(gain(peak,A0,0,-A0,  A0,A1,A2))-3 title "approx -3dB"

I wrote a simple Arduino program to sample the phototransistor every 1/60th of a second, alternating between IR off and IR on. After each IR-on reading, I output the time, the difference between on and off readings, and the filtered difference. (click on the code box to view it)

#include "TimerOne.h"

#define rLED 3
#define irLED 5

// #define CANONICAL   // use canonical, rather than direct implementation of IIR filter
// Direct implementation seems to avoid overflow better.
// There is probably still a bug in the canonical implementation, as it is quite unstable.

#define fs (30) // sampling frequency in Hz
#define half_period (500000L/fs)  // half the period in usec

#define multiplier  32      // power of 2 near fs
#define a1  (-48)           // -(multiplier+k)
#define a2  (17)            // k+1

volatile uint8_t first_tick;    // Is this the first tick after setup?
void setup(void)
{
    Serial.begin(115200);
//    pinMode(rLED,OUTPUT);
    pinMode(irLED,OUTPUT);
//    digitalWrite(rLED,1);  // Turn RED LED off
    digitalWrite(irLED,1); // Turn IR LED off

    Serial.print("# bandpass IIR filter\n# fs=");
    Serial.print(fs);
    Serial.print(" Hz, period=");
    Serial.print(2*half_period);
    Serial.print(" usec\n#  H(z) = ");
    Serial.print(multiplier);
    Serial.print("(1-z^-2)/(");
    Serial.print(multiplier);
    Serial.print(" + ");
    Serial.print(a1);
    Serial.print("z^-1 + ");
    Serial.print(a2);
    Serial.println("z^-2)");
#ifdef CANONICAL
    Serial.println("# using canonical implementation");
#else
    Serial.println("# using direct implementation");
#endif
    Serial.println("#  microsec raw   filtered");

    first_tick=1;
    Timer1.initialize(half_period);
    Timer1.attachInterrupt(half_period_tick,half_period);
}

#ifdef CANONICAL
// for canonical implementation
 volatile int32_t w_0, w_1, w_2;
#else
// For direct implementation
 volatile int32_t x_1,x_2, y_0,y_1,y_2;
#endif

void loop()
{
}

volatile uint8_t IR_is_on=0;    // current state of IR LED
volatile uint16_t IR_off;       // reading when IR is off (stored until next tick)

void half_period_tick(void)
{
    uint32_t timestamp=micros();

    uint16_t IR_read;
    IR_read = analogRead(0);
    if (!IR_is_on)
    {   IR_off=IR_read;
        digitalWrite(irLED,0); // Turn IR LED on
        IR_is_on = 1;
        return;
    }

    digitalWrite(irLED,1); // Turn IR LED off
    IR_is_on = 0;

    Serial.print(timestamp);
    Serial.print(" ");

    int16_t x_0 = IR_read-IR_off;
    Serial.print(x_0);
    Serial.print(" ");

 #ifdef CANONICAL
    if (first_tick)
    {  // I'm not sure how to initialize w for the first tick
       w_2 = w_1 = multiplier*x_0/ (1+a1+a2);
       first_tick = 0;
    }
 #else
    if (first_tick)
    {   x_2 = x_1 = x_0;
        first_tick = 0;
    }
#endif

#ifdef CANONICAL
    w_0 = multiplier*x_0 - a1*w_1 -a2*w_2;
    int32_t y_0 = w_0 - w_2;
    Serial.println(y_0);
    w_2=w_1;
    w_1=w_0;
#else
     y_0 = multiplier*(x_0-x_2) - a1*y_1 -a2*y_2;
     Serial.println(y_0);
     y_0 /= multiplier;
     x_2 = x_1;
     x_1 = x_0;
     y_2 = y_1;
     y_1 = y_0;
#endif
}

Here are a couple of examples of the input and output of the filtering:

(click to embiggen) The input signals here are fairly clean, but different runs often get quite different amounts of light through the finger, depending on which finger is used and the alignment with the phototransistor. Note that the DC offset shifts over the course of each run.

(click to embiggen) After filtering the DC offset and the baseline shift are gone. The two very different input sequences now have almost the same range. There is a large, clean downward spike at the beginning of each pulse.

Overall, I’m pretty happy with the results of doing digital filtering here. Even a crude 2-zero, 2-pole filter using just integer arithmetic does an excellent job of cleaning up the signal.


Filed under: Circuits course, Data acquisition, freshman design seminar Tagged: Arduino, biquad filter, digital filter, IIR filter, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Digital filters for pulse monitor

In Optical pulse monitor with little electronics, I talked a bit about an optical pulse monitor using the Arduino and just 4 components (2 resistors, an IR emitter, and a phototransistor).  Yesterday, I had gotten as far as getting good values for resistors, doing synchronous decoding, and using a very simple low-pass IIR filter to clean up the noise.  The final result still had problems with the baseline shifting (probably due to slight movements of my finger in the sensor):

(click to embiggen) Yesterday’s plot with digital low-pass filtering, using y(t) = (x(t) + 7 y(t-1) )/8.  There is not much noise, but the baseline wobbles up and down a lot, making the signal hard to process automatically.

Today I decided to brush off my digital filter knowledge, which I haven’t used much lately, and see if I could design a filter using only small integer arithmetic on the Arduino, to clean up the signal more. I decided to use a sampling rate fs = 30Hz on the Arduino, to avoid getting any beating due to 60Hz pickup (not that I’ve seen much with my current setup). The 30Hz choice was made because I do two measurements (IR on and IR off) for each sample, so my actual measurements are at 60Hz, and should be in the same place in any noise waveform that is picked up. (Europeans with 50Hz line frequency would want to use 25Hz as their sampling frequency.)

With the 680kΩ resistor that I selected yesterday, the 30Hz sampling leaves plenty of time for the signal to charge and discharge:

The grid line in the center is at 3v. The green trace is the signal to on the positive side of the IR LED, so the LED is on when the trace is low (with 32mA current through the pullup resistor). The yellow trace is the voltage at the Arduino input pin: high when light is visible, low when it is dark. This recording was made with my middle finger between the LED and the phototransistor.

I decided I wanted to replace the low-pass filter with a passband filter, centered near 1Hz (60 beats per minute), but with a range of about 0.4Hz (24 bpm) to 4Hz (240bpm). I don’t need the passband to be particularly flat, so I decided to go with a simple 2-pole, 2-zero filter (called a biquad filter). This filter has the transfer function

To get the gain of the filter at a frequency f, you just compute , where .  Note that the z values that correspond to sinusoids are along the unit circle, from DC at up to the Nyquist frequency at .

The filter is implemented as a simple recurrence relation between the input x and the output y:

This is known as the “direct” implementation.  It takes a bit more memory than the “canonical” implementation, but has some nice properties when used with small-word arithmetic—the intermediate values never get any further from 0 than the output and input values, so there is no overflow to worry about in intermediate computations.

I tried using an online web tool to design the filter http://www-users.cs.york.ac.uk/~fisher/mkfilter/, and I got some results but not everything on the page is working.  One can’t very well complain to Tony Fisher about the maintenance, since he died in 2000. I tried using the tool at http://digitalfilter.com/enindex.html to look at filter gain, but it has an awkward x-axis (linear instead of logarithmic frequency) and was a bit annoying to use.  So I looked at results from Tony Fisher’s program, then used my own gnuplot script to look at the response for filter parameters I was interested in.

The filter program gave me one obvious result (that I should not have needed a program to realize): the two zeros need to be at DC and the Nyquist frequency—that is at ±1.  That means that the numerator of the transfer function is just , and b0=1, b1=0, and b2=–1.  The other two parameters it gave me were a2=0.4327386423 and a1=–1.3802466192.  Of course, I don’t want to use floating-point arithmetic, but small integer arithmetic, so that the only division I do is by powers of 2 (which the compiler turns into a quick shift operation).

I somewhat arbitrarily selected 32 as my power of 2 to divide by, so that my transfer function is now

and my recurrence relation is

with A1 and A2 restricted to be integers.  Rounding the numbers from Fisher’s program suggested A1=-44 and A2=14, but that centered the filter at a bit higher frequency than I liked, so I tweaked the parameters and drew plots to see what the gain function looked like.  I made one serious mistake initially—I neglected to check that the two poles were both inside the unit circle (they were real-valued poles, so the check was just applying the quadratic formula).  My first design (not the one from Fisher’s program) had one pole outside the unit circle—it looked fine on the plot, but when I implemented it, the values grew until the word size was exceeded, then oscillated all over the place.  When I realized what was wrong, I checked the stability criterion and changed the A2 value to make the pole be inside the unit circle.

I eventually ended up with A1=-48 and A2=17, which centered the filter at 1, but did not have as high an upper frequency as I had originally thought I wanted:

(click to embiggen) The gain of the filter that I ended up implementing has -3dB points at about 0.43 and 2.15 Hz.

Here is the gnuplot script I used to generate the plot—it is not fully automatic (the xtics, for example, are manually set). Click it to expand.

fs = 30	# sampling frequency
A0=32.  # multiplier (use power of 2)
b=16.

A1=-(A0+b)
A2=b+1

peak = fs/A0	# approx frequency of peak of filter

set title sprintf("Design of biquad filter, fs=%3g Hz",fs)

set key bottom center
set ylabel "gain [dB]"
unset logscale y
set yrange [-20:30]

set xlabel "frequency [Hz]"
set logscale x
set xrange [0.01:0.5*fs]

set xtics add (0.43, 2.15)
set grid xtics

j=sqrt(-1)
biquad(zinv,b0,b1,b2,a0,a1,a2) = (b0+zinv*(b1+zinv*b2))/(a0+zinv*(a1+zinv*a2))
gain(f,b0,b1,b2,a0,a1,a2) = abs( biquad(exp(j*2*pi*f/fs),b0,b1,b2,a0,a1,a2))
phase(f,b0,b1,b2,a0,a1,a2) = imag(log( biquad(exp(j*2*pi*f/fs),b0,b1,b2,a0,a1,a2)))

plot 20*log(gain(x,A0,0,-A0,  A0,A1,A2)) \
		title sprintf("%.0f (1-z^-2)/(%.0f+ %.0f z^-1 + %.0f z^-2)", \
			A0, A0, A1, A2), \
	20*log(gain(peak,A0,0,-A0,  A0,A1,A2))-3 title "approx -3dB"

I wrote a simple Arduino program to sample the phototransistor every 1/60th of a second, alternating between IR off and IR on. After each IR-on reading, I output the time, the difference between on and off readings, and the filtered difference. (click on the code box to view it)

#include "TimerOne.h"

#define rLED 3
#define irLED 5

// #define CANONICAL   // use canonical, rather than direct implementation of IIR filter
// Direct implementation seems to avoid overflow better.
// There is probably still a bug in the canonical implementation, as it is quite unstable.

#define fs (30) // sampling frequency in Hz
#define half_period (500000L/fs)  // half the period in usec

#define multiplier  32      // power of 2 near fs
#define a1  (-48)           // -(multiplier+k)
#define a2  (17)            // k+1

volatile uint8_t first_tick;    // Is this the first tick after setup?
void setup(void)
{
    Serial.begin(115200);
//    pinMode(rLED,OUTPUT);
    pinMode(irLED,OUTPUT);
//    digitalWrite(rLED,1);  // Turn RED LED off
    digitalWrite(irLED,1); // Turn IR LED off

    Serial.print("# bandpass IIR filter\n# fs=");
    Serial.print(fs);
    Serial.print(" Hz, period=");
    Serial.print(2*half_period);
    Serial.print(" usec\n#  H(z) = ");
    Serial.print(multiplier);
    Serial.print("(1-z^-2)/(");
    Serial.print(multiplier);
    Serial.print(" + ");
    Serial.print(a1);
    Serial.print("z^-1 + ");
    Serial.print(a2);
    Serial.println("z^-2)");
#ifdef CANONICAL
    Serial.println("# using canonical implementation");
#else
    Serial.println("# using direct implementation");
#endif
    Serial.println("#  microsec raw   filtered");

    first_tick=1;
    Timer1.initialize(half_period);
    Timer1.attachInterrupt(half_period_tick,half_period);
}

#ifdef CANONICAL
// for canonical implementation
 volatile int32_t w_0, w_1, w_2;
#else
// For direct implementation
 volatile int32_t x_1,x_2, y_0,y_1,y_2;
#endif

void loop()
{
}

volatile uint8_t IR_is_on=0;    // current state of IR LED
volatile uint16_t IR_off;       // reading when IR is off (stored until next tick)

void half_period_tick(void)
{
    uint32_t timestamp=micros();

    uint16_t IR_read;
    IR_read = analogRead(0);
    if (!IR_is_on)
    {   IR_off=IR_read;
        digitalWrite(irLED,0); // Turn IR LED on
        IR_is_on = 1;
        return;
    }

    digitalWrite(irLED,1); // Turn IR LED off
    IR_is_on = 0;

    Serial.print(timestamp);
    Serial.print(" ");

    int16_t x_0 = IR_read-IR_off;
    Serial.print(x_0);
    Serial.print(" ");

 #ifdef CANONICAL
    if (first_tick)
    {  // I'm not sure how to initialize w for the first tick
       w_2 = w_1 = multiplier*x_0/ (1+a1+a2);
       first_tick = 0;
    }
 #else
    if (first_tick)
    {   x_2 = x_1 = x_0;
        first_tick = 0;
    }
#endif

#ifdef CANONICAL
    w_0 = multiplier*x_0 - a1*w_1 -a2*w_2;
    int32_t y_0 = w_0 - w_2;
    Serial.println(y_0);
    w_2=w_1;
    w_1=w_0;
#else
     y_0 = multiplier*(x_0-x_2) - a1*y_1 -a2*y_2;
     Serial.println(y_0);
     y_0 /= multiplier;
     x_2 = x_1;
     x_1 = x_0;
     y_2 = y_1;
     y_1 = y_0;
#endif
}

Here are a couple of examples of the input and output of the filtering:

(click to embiggen) The input signals here are fairly clean, but different runs often get quite different amounts of light through the finger, depending on which finger is used and the alignment with the phototransistor. Note that the DC offset shifts over the course of each run.

(click to embiggen) After filtering the DC offset and the baseline shift are gone. The two very different input sequences now have almost the same range. There is a large, clean downward spike at the beginning of each pulse.

Overall, I’m pretty happy with the results of doing digital filtering here. Even a crude 2-zero, 2-pole filter using just integer arithmetic does an excellent job of cleaning up the signal.


Filed under: Circuits course, Data acquisition, freshman design seminar Tagged: Arduino, biquad filter, digital filter, IIR filter, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Optical pulse monitor with little electronics

In yesterday’s blog post, I talked mainly about what my son did with his time yesterday, to mention the small amount of debugging help I gave him.  Today I’ll post about what I did with most of my time yesterday.

This year, I am hoping to lead a 2-unit freshman design seminar for bioengineering students.  (Note: I did not say “teach” here, as I’m envisioning more of a mentoring role than a specific series of exercises.)  One thing I’m doing is trying to come up with design projects that freshmen with essentially no engineering skills can do as a team.  They may have to learn something new (I certainly hope they do!), but they should only spend a total of 60 hours on the course, including class time.  Since I want to spend some of class time on lab tours, lab safety, using the library resources, and how to work in a group effectively, there is not a lot of time left for the actual design and implementation.

One of the things I found very valuable in designing the Applied Circuits course was doing all the design labs myself, sometimes several times, in order to tweak the specs and anticipate where the students would have difficulty.  I expect to do some redesign of a couple of the circuits labs this year, but that course is scheduled for Spring (and finally got official approval this week), while the (not yet approved) freshman seminar is scheduled for Winter.  So I’m now experimenting with projects that I think may be suitable for the freshman design seminar.

These students cannot individually be expected to know anything useful, high school in California being what it is.  As a group, though, I think I can expect a fair amount of knowledge of biology, chemistry, and physics, with perhaps a sprinkling of math and computer programming.  I can’t expect any electronics knowledge, and we won’t have access to a machine shop—we may get permission for the students to use a laser cutter under supervision.  We can probably get some space in an electronics lab, but maybe not in a bio lab (the dean took away the department’s only teaching lab, with a “promise” to build a bigger one—but it is unlikely to be available for the freshmen by Winter quarter—I miss our first dean of engineering, as we seem to have had a series of incompetent deans since then).

So I’m looking for projects that can essentially be built at home with minimal tools and skills, but that are interesting enough to excite students to continue to higher levels in the program.  And I want them to be design projects, not kit-building or cookbook projects, with multiple possible solutions.

So far, there have been a couple of ideas suggested, both involving a small amount of electronics and some mechanical design:

  • An optical growth meter for continuously monitoring a liquid culture of bacteria or yeast. The electronics here is just a light source (LED or laser diode with current-limiting resistor), a phototransistor,  a current-to-voltage converter for the phototransistor (one resistor), and a data logger (like the Arduino Data Logger we use for the circuits course).  The hard part is coming up with a good way to get uniform sampling of the liquid culture while it is in an incubator on a shaker table.  There are lots of possible solutions: mounting stuff around flasks, immersed sensors, bending glass tubing so that the swirling culture is pumped through the tubes, external peristaltic pumps, … .  Design challenges include how the parts of the apparatus that touch the culture will be sterilized, how to keep things from falling apart when they are shaken for a couple of days, and so forth.   I’ve not even started trying to do a design here, though I probably should, as the mechanical design is almost all unfamiliar to me, and I’d be a good example of the cluelessness that the students would bring to the project.
  • An optical pulse sensor or pulse oximeter.  This is the project I decided to work on yesterday. The goal is to shine light through a finger and get a good pulse signal.  (I tried this last summer, making a very uncomfortable ear clip and doing a little testing before rejecting the project for the circuits course.)  If I can get good pulse signals from both red and IR light sources, I should be able to take differences or ratios and get an output proportional to blood oxygenation.

I decided yesterday to try to build a pulse monitor with almost no electronics.  In particular, I wanted to try building without an op amp or other amplifier, feeding the phototransistor signal directly into an Arduino analog in.  (I may switch to using the KL25Z for this project, as the higher resolution on the analog-to-digital converter means I could use smaller signals without amplification.)

A phototransistor is essentially a light-to-current converter.  The current through the phototransistor is essentially linear in the amount of light, over a pretty wide range. The Arduino analog inputs are voltage sensors, so we need to convert the current to a voltage.  The simplest way to do this is to put a series resistor to ground, and measure the voltage across the series resistor.  The voltage we see is then the current times the resistance.  Sizing the resistor is a design task—how big a current do we get with the intensity of light through the finger, and how much voltage do we need. The voltage needed can be estimated from the resolution of the analog-to-digital converter, but the amount of light is best measured empirically.

One problem that the pulse monitor faces is huge variations in ambient light.  Ideally the phototransistor gets light only from LED light shining through the finger, but that is a bit hard to set up while breadboarding.  Distinguishing the ambient light from the light through the finger can be difficult. Yesterday, I tried to reduce that problem by using “synchronous decoding”.  That is, I turned the LED on and off, and measured the difference between the phototransistor current with the LED on and with the LED off.  Using the Arduino to control the LED as well as to read the voltage is fairly easy—these are the sorts of tasks that are starter projects on the Arduino, so should be within the capabilities of the freshmen (with some learning on their part).

I also looked at the phototransistor output with my BitScope oscilloscope, so that I could see the waveform that the Arduino was sampling two points from.  Here is an example waveform:

The x-axis is 20ms/division, and the y-axis 1v/division, with the center line at 2v.
I put in a 50% duty cycle (20ms on, 20ms off).  The IR light is shining through my index finger.

For the above trace, I used a 680kΩ pulldown resistor to convert the current to voltage. I played a lot with different resistors yesterday, to get a feel for the tradeoffs.  Such a large resistor provides a large voltage swing for a small change in current, but the parasitic capacitance makes for rather slow RC charge/discharge curves.  Using larger resistors does not result in larger swings (unless the frequency of the input is reduced), because the RC time constant gets too large and the slowly changing signal does not have time to make a full swing.  I tried, as an experiment, adding a unity-gain buffer, so that the BitScope and Arduino inputs would not be loading the phototransistor.  This did not make much difference, so most of the parasitic capacitance is probably in the phototransistor itself.  One can get faster response for a fixed change in light only by decreasing the voltage swing, which would then require amplification to get a big enough signal to be read by the Arduino.  (It may be that the extra 6 bits of resolution on the KL25Z board would allow a resistor as low as 20kΩ and much faster response.)

Note that ambient light results in a DC shift of the waveform without a change in shape, until it gets bright enough that the current is more than 5v/680kΩ (about 7µA), at which point the signal gets clipped.  Unfortunately, ordinary room lighting is enough to saturate the sensor with this large a series resistor.  I was able to get fairly consistent readings by using the clothespin ear clip I made last summer, clamped open to make it the right size for my finger.  I did even better when I put the clip and my hand into a camera bag that kept out most of the ambient light.  Clearly, mechanical design for eliminating ambient light will be a big part of this design.

One might think that the 2v signal seen on the BitScope is easily big enough for pulse detection, but remember that this is not the signal we are interested in.  The peak-to-peak voltage is proportional to how transparent the finger is—we are interested in the variation of that amplitude with blood flow.  Here is an example plot of the sort of signal we are looking at:

(click to embiggen) The pulse here is quite visible, but is only about a 15–30 count change in the 300-count amplitude signal. Noise from discretization (and other sources) makes the signal hard to pick out auotmatically.  This signal was recorded with the Arduino data logger, but only after I had modified the data logger code to turn the IR emitter on and off and report differences in the readings rather than the readings themselves. Note the sharp downward transition (increased opacity due to more blood) at the beginning of each pulse.

To get a bigger, cleaner signal, I decided to do some very crude low-pass filtering on the Arduino. I used the simplest of infinite-impulse response (IIR) filters: . Because division is very slow on the Arduino, I limited myself to simple shifts for division: a= 1/2, 1/4, or 1/8. To avoid losing even more precision, I actually output then divided by 8 to get Y(t). I also used a 40msec sampling period, with the IR emitter on for 20ms, then off for 20msec (the waveform shown in the oscilloscope trace above).

(click to embiggen) With digital low-pass filtering, the pulse signal is much cleaner, but the sharp downward transition at the start of each pulse has been rounded off by the filter. This data was not captured with the Arduino Data Logger, but by cutting and pasting from the Arduino serial monitor, which involves simpler (hence more feasible for freshmen) programming of the Arduino.

I now have a very clean pulse signal, using just the Arduino, an IR emitter, a phototransistor, and two resistors. There is still a huge offset, as the signal is 200 counts out of 4600, and the offset fluctuates slowly.  To get a really good signal, I’d want to do a bandpass filter that passes 0.3Hz to 3Hz (20bpm–200bpm), but designing that digital filter would be beyond the scope of a freshman design seminar.  Even the simple IIR filter is pushing a bit here.

I’m not sure how to go from here to the pulse oximeter (using both an IR and a red LED) without fancy digital filtering.  Here is the circuit so far:

Although the 120Ω resistor allows up to 32mA, I didn’t believe that the Arduino outputs could actually sink that much current—20 mA is what the spec sheet allows. Checking with the BitScope, I see a 3840mV drop across the resistor, for 32mA. Note: I used pins D3 and D5 of the Arduino so that I could use pulse-width modulation (PWM) if I wanted to. (Schematic drawn with Digikey’s SchemeIt.)


Filed under: Circuits course, Data acquisition, freshman design seminar Tagged: Arduino, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Optical pulse monitor with little electronics

In yesterday’s blog post, I talked mainly about what my son did with his time yesterday, to mention the small amount of debugging help I gave him.  Today I’ll post about what I did with most of my time yesterday.

This year, I am hoping to lead a 2-unit freshman design seminar for bioengineering students.  (Note: I did not say “teach” here, as I’m envisioning more of a mentoring role than a specific series of exercises.)  One thing I’m doing is trying to come up with design projects that freshmen with essentially no engineering skills can do as a team.  They may have to learn something new (I certainly hope they do!), but they should only spend a total of 60 hours on the course, including class time.  Since I want to spend some of class time on lab tours, lab safety, using the library resources, and how to work in a group effectively, there is not a lot of time left for the actual design and implementation.

One of the things I found very valuable in designing the Applied Circuits course was doing all the design labs myself, sometimes several times, in order to tweak the specs and anticipate where the students would have difficulty.  I expect to do some redesign of a couple of the circuits labs this year, but that course is scheduled for Spring (and finally got official approval this week), while the (not yet approved) freshman seminar is scheduled for Winter.  So I’m now experimenting with projects that I think may be suitable for the freshman design seminar.

These students cannot individually be expected to know anything useful, high school in California being what it is.  As a group, though, I think I can expect a fair amount of knowledge of biology, chemistry, and physics, with perhaps a sprinkling of math and computer programming.  I can’t expect any electronics knowledge, and we won’t have access to a machine shop—we may get permission for the students to use a laser cutter under supervision.  We can probably get some space in an electronics lab, but maybe not in a bio lab (the dean took away the department’s only teaching lab, with a “promise” to build a bigger one—but it is unlikely to be available for the freshmen by Winter quarter—I miss our first dean of engineering, as we seem to have had a series of incompetent deans since then).

So I’m looking for projects that can essentially be built at home with minimal tools and skills, but that are interesting enough to excite students to continue to higher levels in the program.  And I want them to be design projects, not kit-building or cookbook projects, with multiple possible solutions.

So far, there have been a couple of ideas suggested, both involving a small amount of electronics and some mechanical design:

  • An optical growth meter for continuously monitoring a liquid culture of bacteria or yeast. The electronics here is just a light source (LED or laser diode with current-limiting resistor), a phototransistor,  a current-to-voltage converter for the phototransistor (one resistor), and a data logger (like the Arduino Data Logger we use for the circuits course).  The hard part is coming up with a good way to get uniform sampling of the liquid culture while it is in an incubator on a shaker table.  There are lots of possible solutions: mounting stuff around flasks, immersed sensors, bending glass tubing so that the swirling culture is pumped through the tubes, external peristaltic pumps, … .  Design challenges include how the parts of the apparatus that touch the culture will be sterilized, how to keep things from falling apart when they are shaken for a couple of days, and so forth.   I’ve not even started trying to do a design here, though I probably should, as the mechanical design is almost all unfamiliar to me, and I’d be a good example of the cluelessness that the students would bring to the project.
  • An optical pulse sensor or pulse oximeter.  This is the project I decided to work on yesterday. The goal is to shine light through a finger and get a good pulse signal.  (I tried this last summer, making a very uncomfortable ear clip and doing a little testing before rejecting the project for the circuits course.)  If I can get good pulse signals from both red and IR light sources, I should be able to take differences or ratios and get an output proportional to blood oxygenation.

I decided yesterday to try to build a pulse monitor with almost no electronics.  In particular, I wanted to try building without an op amp or other amplifier, feeding the phototransistor signal directly into an Arduino analog in.  (I may switch to using the KL25Z for this project, as the higher resolution on the analog-to-digital converter means I could use smaller signals without amplification.)

A phototransistor is essentially a light-to-current converter.  The current through the phototransistor is essentially linear in the amount of light, over a pretty wide range. The Arduino analog inputs are voltage sensors, so we need to convert the current to a voltage.  The simplest way to do this is to put a series resistor to ground, and measure the voltage across the series resistor.  The voltage we see is then the current times the resistance.  Sizing the resistor is a design task—how big a current do we get with the intensity of light through the finger, and how much voltage do we need. The voltage needed can be estimated from the resolution of the analog-to-digital converter, but the amount of light is best measured empirically.

One problem that the pulse monitor faces is huge variations in ambient light.  Ideally the phototransistor gets light only from LED light shining through the finger, but that is a bit hard to set up while breadboarding.  Distinguishing the ambient light from the light through the finger can be difficult. Yesterday, I tried to reduce that problem by using “synchronous decoding”.  That is, I turned the LED on and off, and measured the difference between the phototransistor current with the LED on and with the LED off.  Using the Arduino to control the LED as well as to read the voltage is fairly easy—these are the sorts of tasks that are starter projects on the Arduino, so should be within the capabilities of the freshmen (with some learning on their part).

I also looked at the phototransistor output with my BitScope oscilloscope, so that I could see the waveform that the Arduino was sampling two points from.  Here is an example waveform:

The x-axis is 20ms/division, and the y-axis 1v/division, with the center line at 2v.
I put in a 50% duty cycle (20ms on, 20ms off).  The IR light is shining through my index finger.

For the above trace, I used a 680kΩ pulldown resistor to convert the current to voltage. I played a lot with different resistors yesterday, to get a feel for the tradeoffs.  Such a large resistor provides a large voltage swing for a small change in current, but the parasitic capacitance makes for rather slow RC charge/discharge curves.  Using larger resistors does not result in larger swings (unless the frequency of the input is reduced), because the RC time constant gets too large and the slowly changing signal does not have time to make a full swing.  I tried, as an experiment, adding a unity-gain buffer, so that the BitScope and Arduino inputs would not be loading the phototransistor.  This did not make much difference, so most of the parasitic capacitance is probably in the phototransistor itself.  One can get faster response for a fixed change in light only by decreasing the voltage swing, which would then require amplification to get a big enough signal to be read by the Arduino.  (It may be that the extra 6 bits of resolution on the KL25Z board would allow a resistor as low as 20kΩ and much faster response.)

Note that ambient light results in a DC shift of the waveform without a change in shape, until it gets bright enough that the current is more than 5v/680kΩ (about 7µA), at which point the signal gets clipped.  Unfortunately, ordinary room lighting is enough to saturate the sensor with this large a series resistor.  I was able to get fairly consistent readings by using the clothespin ear clip I made last summer, clamped open to make it the right size for my finger.  I did even better when I put the clip and my hand into a camera bag that kept out most of the ambient light.  Clearly, mechanical design for eliminating ambient light will be a big part of this design.

One might think that the 2v signal seen on the BitScope is easily big enough for pulse detection, but remember that this is not the signal we are interested in.  The peak-to-peak voltage is proportional to how transparent the finger is—we are interested in the variation of that amplitude with blood flow.  Here is an example plot of the sort of signal we are looking at:

(click to embiggen) The pulse here is quite visible, but is only about a 15–30 count change in the 300-count amplitude signal. Noise from discretization (and other sources) makes the signal hard to pick out auotmatically.  This signal was recorded with the Arduino data logger, but only after I had modified the data logger code to turn the IR emitter on and off and report differences in the readings rather than the readings themselves. Note the sharp downward transition (increased opacity due to more blood) at the beginning of each pulse.

To get a bigger, cleaner signal, I decided to do some very crude low-pass filtering on the Arduino. I used the simplest of infinite-impulse response (IIR) filters: . Because division is very slow on the Arduino, I limited myself to simple shifts for division: a= 1/2, 1/4, or 1/8. To avoid losing even more precision, I actually output then divided by 8 to get Y(t). I also used a 40msec sampling period, with the IR emitter on for 20ms, then off for 20msec (the waveform shown in the oscilloscope trace above).

(click to embiggen) With digital low-pass filtering, the pulse signal is much cleaner, but the sharp downward transition at the start of each pulse has been rounded off by the filter. This data was not captured with the Arduino Data Logger, but by cutting and pasting from the Arduino serial monitor, which involves simpler (hence more feasible for freshmen) programming of the Arduino.

I now have a very clean pulse signal, using just the Arduino, an IR emitter, a phototransistor, and two resistors. There is still a huge offset, as the signal is 200 counts out of 4600, and the offset fluctuates slowly.  To get a really good signal, I’d want to do a bandpass filter that passes 0.3Hz to 3Hz (20bpm–200bpm), but designing that digital filter would be beyond the scope of a freshman design seminar.  Even the simple IIR filter is pushing a bit here.

I’m not sure how to go from here to the pulse oximeter (using both an IR and a red LED) without fancy digital filtering.  Here is the circuit so far:

Although the 120Ω resistor allows up to 32mA, I didn’t believe that the Arduino outputs could actually sink that much current—20 mA is what the spec sheet allows. Checking with the BitScope, I see a 3840mV drop across the resistor, for 32mA. Note: I used pins D3 and D5 of the Arduino so that I could use pulse-width modulation (PWM) if I wanted to. (Schematic drawn with Digikey’s SchemeIt.)


Filed under: Circuits course, Data acquisition, freshman design seminar Tagged: Arduino, IR emitter, LED, phototransistor, pulse, pulse monitor, pulse oximeter

Random thoughts on circuits labs

DNA melting

I spent some time yesterday thinking about whether we could do optical detection of DNA (particularly some variant of the DNA melting lab from MIT—see also the Fall 2008 class handouts).  I noted in the 2008 handouts that they were using a blue LED array driven by a 0.29A current source (made from an LM317T voltage regulator, a rather inefficient method). The wiki page uses a regulated 5V supply and a 25Ω series resistor, which would be around 60–70mA for a typical forward drop of 3.2–3.5V in a blue LED.  That’s still a pretty powerful light source for an LED. They say they are using LZ1-00B200, which has a 3.6V forward voltage, but can handle a full amp of current, so is more LED than is needed.

We can get a blue LED for under $2 that can handle 50mA continuously (LTL911CBKS5), though it has a forward voltage of typically 4.3V.  In surface mount for $1.14, we could get MLEBLU-A1-0000-000T01, which has a dominant wavelength of 465–485nm (depending on bin code) and a luminous flux of 10.7 lm at 150mA (forward voltage 3.2V).  I estimate the LED MIT mentions produces about 6lm at that current.  The expensive part of the illumination is not the LED, but the focusing lenses to concentrate the light and the optical filtering needed to keep the excitation wavelength from being detected by the photodiode.

I was thinking that it would be cool to use a laser as an excitation source, rather than an LED, since then no lenses or filter would be needed on the source—just a blocking filter on the photoreceptor. Unfortunately, blue lasers are very expensive.  What are cheap are the blue-violet lasers at 405nm, since the laser diodes are made in quantity for BluRay players. (Amazon has 405nm laser pointers for under $10 with shipping.) Unfortunately the usual fluorescent dyes used for DNA melting measurements (SYBR Green, LC Green Plus, EvaGreen) are not excited at 405nm, and need excitation wavelengths in the range 440nm–470nm).  I’ve been wondering whether one of the 405nm-sensitive dyes used in flow cytometry (like Sytox Blue dead cell stain) could be used.  But I’ve not found a double-stranded DNA dye for sale that is easily excited at 405nm (even Sytox Blue is way down in sensitivity from its peak), so laser excitation seems to be out—the excitation wavelengths needed for standard dyes require fairly expensive lasers.  The benchtop lasers usually used in labs and flow cytometry equipment are priced in the “if-you-have-to-ask” price range.  Buying enough copies for a student lab is more than this lab is worth.

I still don’t see a way to make the DNA melting curve project work within our course.  Even MIT gives up half a semester to this lab, and we don’t have that much time (nor that caliber of students, on average).

Soldering project

I want the students to learn to solder (at least through-hole parts, not necessarily surface-mount). I don’t want to do the traditional blinky-light soldering practice, so I’ve been looking for a place in the course where it makes sense to require soldering, rather than wiring up a breadboard.

Breadboards have problems with loose wires, so the more complex the circuit, the more problems a breadboard causes.  Breadboards also have problems connecting to wires that have to leave the breadboard—particularly wires to moving objects.  This suggests that the EKG/EMG circuit would be the most appropriate as a soldering project, as it is fairly complicated and the long wires to the Ag/AgCl gel electrodes can cause a lot of problems with loose connections (my first check on debugging is to wiggle the header pins for those wires).

But I want the students to be doing some designing for the EKG circuit, not just soldering up a predetermined circuit, so I’m thinking of designing an instrumentation-amp protoboard, which has an ina126 instrumentation amp and an MCP6002 dual op amp chip, with power pins wired up and a place for the Rgain resistor and bypass capacitors, but everything else in a breadboard-like configuration, so that resistors, capacitors, and jumper wires could be added.   Off-board connections could be done with screw terminals to make sturdy connections.

My son and I came up with the further idea of adding an optional LED output, to make a blinky-light-EKG device.  I think that the approximately 1.5V, 30msec pulse that I was seeing for the R segment of the EKG would be enough to make a visible flash—I’ll have to try it out on my breadboard.  I tried it today, but I was only seeing 0.5V pulses today (poorer contact with the electrodes?), and I had to raise the 3.9kΩ feedback resistor to 10kΩ to increase the gain of the final stage., which was enough to get weak flashes from an LED with a 100Ω series resistor.  Because the op amp has limited output current (±23mA short circuit), I felt it fairly safe to put the LED directly between the op amp output and the Vref signal, which gives a good flash even with a green LED.

The lower voltage that I got this time (until I raised the gain) makes it clear that if I do make an EKG protoboard, it should have room for some trim pots for adjusting the final gain.


Filed under: Circuits course Tagged: Arduino, bioengineering, blinking light, circuits, course design, DNA melting, ECG, EKG, electrocardiogram, instrumentation amplifier, laser, op amp, pulse, violet lasers

More thoughts on EKG

Before doing the EKG lab, we should definitely discuss safety concerns,  including things like the following chart (information from http://electronicstechnician.tpub.com/14086/css/14086_34.htm):

Human reaction at 60Hz Current in mA
 Perception—slight tingling sensation  1.1
 Can’t let go (120 lb. person)—arm and hand muscles close involuntarily  10.0
 Can’t let go (175 lb. person)  16.0
 Can’t breathe—paralysis of the chest muscles  18.0
 Heart fibrillation—rapid irregular contractions of the heart muscles, which could be fatal  65.0

The very small voltages we work with (5–10 V DC) means that we rarely need to be concerned about safety issues in the lab. Most of the resistance of the body comes from the skin, and varies enormously according to how sweaty the skin is. Cleaning dead skin cells off (as is done with most preps for EKG electrodes) reduces the resistance of the skin quite a bit. DC is somewhat safer than AC, because skin is less conducting than the rest of the body, and so acts as a capacitor in parallel with a resistor. Puncturing or scraping the skin reduces resistance considerably.

It would probably be useful to have students measure the resistance between two Ag/AgCl electrodes and compute the currents that would flow at different voltages. When I tried this on two chest electrodes (just after showering, so clean, damp skin) I measured around 50kΩ. Pressing the electrodes more firmly against the skin dropped the resistance to 25 kΩ, and it gradually crept back up.

I keep thinking that the 3-wire design for EKGs is overkill. The 3rd wire seems to be just provided to bias the body to be between the power rails of the instrumentation amplifier. It should be sufficient to bias one of the electrodes with a large resistor to the reference voltage directly, rather than through the body.

I tried this.  First I hooked up the 3-wire system of the 2-stage EKG amplifier (though there was a mistake on that post, as the Rgain resistor was really 4.7kΩ, not 820Ω).  This was to make sure that I was getting good contacts and a clean signal. I then disconnected the bias lead and tried to bias the opposite end of the wires.  This did not work at all.  Disconnecting the bias wire resulted in a large signal with a period of 16.7ms (60Hz, though with a complex waveform).  Adding resistors between Vplus and Vref, Vminus and Vref, or both, just made this noise worse.  I then tried taking my body out of the loop, connecting a 25 kΩ resistor between the clip leads.  Without the biasing resistors I saw the same complex 60Hz signal.  It seems to come from capacitive coupling to the leads, as moving my hand closer or further from the leads changes the magnitude of the signal, and grounding myself eliminates it.  Putting 24kΩ resistors between Vplus and Vref and between Vminus and Vref reduced the noise, but did not eliminate it.  Touching either Vplus or Vminus was enough to produce huge noise again.

I tried another experiment, where I attached the ground electrode not to Vref directly, but through a 0.56 μF capacitor.  This worked fine, even though there was no DC bias connection for the instrumentation amp inputs!  It stopped working if I then touched either the +5V or 0V power rail—the DC bias is important, but my body was working as a pretty good capacitor, holding the DC bias for quite a while.  It is clear that the AC path to ground is crucial also.

I found that I could clean up the EKG signal by putting a 0.56 μF capacitor between Vplus and Vminus—enough that the P part of the EKG was visible.

Clean EMG with P,Q,R,S,T parts of signal all clearly visible. The remaining noise seems to be mainly quantization noise in the Arduino analog-to-digital converter, which could be reduced by increasing the amplifier gain.

Since the remaining noise seemed to be all quantization noise, I upped the amplifier gain.  Trying to raise the gain on the first stage did not work, so I raised the gain on the second stage.

Higher gain EKG circuit, with capacitor on the inputs.  The first-stage gain should be 22.02, and the second stage  18.73, for a total gain of 412.4.

The higher gain amplifier did produce good traces, with less evidence of quantization noise:

The “Arduino units” are 4.967 V/ 1024 = 4.851 mV at the output of the EKG, or 11.76µV at the electrodes. The R peaks are about 3.9mV and the S dips about -0.7mV.  The first R-R interval is 1.368 seconds for a pulse rate of 43.86 bpm.

One thing that is important—the EKG readings are resting EKGs.  If I flex the left pectoral muscle, I can swamp out the EKG signal.

Every EKG is also an EMG (electromyograph), and flexing muscles between the electrodes (here the left pectoral muscle) can swamp out the EKG signal. I computed the electrode voltage from the recorded signal, the measured Arduino A-to-D reference voltage, and the gain of the EKG amplifier. The zero-reference is determined by recording the Vref signal as well as the EKG output signal. The quantization noise from the A-to-D converter is about 3μV (less than 1 pixel in this picture).


Filed under: Circuits course, Data acquisition Tagged: Arduino, bioengineering, circuits, course design, ECG, EKG, electrocardiogram, instrumentation amplifier, op amp, pulse