While I haven’t been active here, I’ve been busy and waiting for parts. So the ADS1299 dev board has arrived and I’ve gotten it working-sort of. I’ve also migrated a bunch of work from using the mbed website to using STM32Cube+SW4ST32.

As a test I hooked the DAC output for the nucleo into the channel one for the ADS1299 (top plot), and programmed it to output a sawtooth wave. The other channels are all various internal things that the IC can be connected to depending on the settings loaded into the registers. For example, the fourth plot down is an internally generated square wave for tests, and the one below that is the internal temperature sensor. I’ve switched also switched to outputting data in a raw format over serial instead of ascii. On the host side this looks like:

import serial
for i in range(sample_batch):
  for j in range(n_channels):

Unfortunately, there are more issues. When using actual electrodes (3′ in length), the signal is again dominated by 60Hz. To electrically isolate the board, I’m giving it it’s own battery supply (using 2 18650s in series), and using optocouplers. The optocouplers I have are too slow (see next graph), so I’ve been waiting on faster ones since then.

The signal out of the optocoupler (bottom) never has time to fall between bits (hard to see because multiple traces are overlaid).

I also let the magic blue smoke out of the MAX30102 board after roughly mounting it into a strap with the GSR electrodes and powering it on :(.

Photoplethysmogram 2

The MAX30102 arrived and I spent some time. I’ve also gotten metal disks and will try to make rings with polymer clay to hold the electrodes for GSR on better. As such I’m busy and this will be brief.

The device itself is tiny.

After reading through the datasheets, I wrote something to set registers for SpO2 measurements (IR and red LEDs active, there’s a heart rate mode with only one), and after having bad luck with guessing appropriate settings, eventually found all the recommended settings in the application notes for the demonstration board.

I had a bit of difficulty getting data from it, if just because it’s smart. There’s a 32 sample FIFO circular buffer for the data, which is accessed by repeated reading a single byte register. The read and write pointers are accessible but unnessesary for this, as they both automatically increment. Samples are 2 24 bit numbers (IR and red channel). As is, the program I’m using to read data sets an interrupt enable flag on the MAX30102 to check it for available data and then checks it repeatedly. There is also an almost full interrupt, and I spent some time getting the MAX30102 to trigger the nucleo, but I’m still having trouble reading multiple samples from the ADC.

See, which I will hopefully have enough time to make nice because I plan to use this with hand tempurature and GSR for biofeedback.

Anyway, in the end I got a reasonable trace for reflectance values.

RED and IR reflectance values

Galvinic Skin Response 2

I’ve been back to working on GSR, trying to give it an actual test rather than making sure there’s any response at all.

I’ve switched to make one of the inamp inputs be from the DAC on the nucleo so I can switch that voltage to keep it in range. The DAC output is in orange, the voltage across my fingers is in blue, t is in .1 seconds.

I’ve also used cable organizers to secure the electrodes and switched to gold plated electrodes. I don’t think the shape is optimal for keeping a good contact with the skin, but that’s something else I can play with. These aren’t that bad-I can type and work with them on atleast.

The inamp has an amplification of 100X, and the voltage out from the ADC is missing a factor of 3.3V.

I need to read the Boucsein book again to see if there’s typical filtering that’s used on the output and try and determine if there’s a good test.

In the end, I still don’t have a good test.


Apparently, everything I want has already been done, and cheaper.

I had assumed this was niche enough not to exist, but there are apparently ICs that solve all my problems. I pride myself on not being the type of autist who wastes his time recreating work without cause, so I’m going to order some to play with.

For pulse oximetry:–ND/6123035

For EEG:

Photoplethysmogram part 1

In which I trudge through some simple tests and realize it helps to read a bit before starting things. Today I tried to make a very very simple photoplethysmogram (light-enlargment-gram). Flesh is relatively transparent to red and infrared light, and that changes with the amounts of blood in one’s tissue. This can be used to measure heart rate. The light absorption of hemoglobin changes depending on whether it is attached to oxygen or not. This can be used to measure heart rate too, as well as oxygen saturation (pulse oximetry). (PPG)

A nice combination of sensors for a wearable watch+ring would be PPG, perifereal temperature and galvinic skin response. I spent a couple of hours trying to get a basic PPG with some IR LEDs and photodiodes. Unfortunately I charged ahead without reading anything and now realize that PPGs are done differently from what I had assumed. Basically, I was just trying to measure IR light reflected (diffusely) by tissue over time.

I bought some 940 nm IR LEDs and photodiodes and made a photointerrupter as a test (read: pointed them at each other and looked at voltages as I put my hand between them). I also played with them as a distance sensor by reflecting the IR off of objects. This was neat.

IR led (which has a neat blue glow on camera) and photodiode, with voltage measured by the oscilloscope. I tried multiple distances and orientations.

Unfortunately there was no obvious change in reflected IR during a heartbeat when they were pointed into my wrist. I moved them much closer, which caused the diode to always be saturated. I then tried it with a shield around the IR led made of tin foil, securing them together with hot glue. The diode was always saturated in this case as well.

I then tried seperating them with a peice of cardboard. This worked and generated a very small signal fluctuating with my heart beat when it was pressed against flesh. I’m not confident that this was PPG as opposed to just changes in distance and pressure.

For PPG beyond wikipedia:


  • For PPG, only 940nm is displayed (as above).
  • Finger tips are the best position (assuming transmission here).
  • Strain gauges have been used to measure heart rate.

For pulse oximetry:

Oximetry is done with a pair of LEDs, a red (660 nm) and an IR one (940nm). Hemoglobin with oxygen absorbs more infrared (NOTE: the paper has an error here “more infrared light (660 nm wavelength) and lesser red light (940 nm wavelength) than Hb.” reverses the frequencies compared to the colors).

Stolen from

The ratio of the varying to constant intensities of each LED color is calculated, and the ratio of the two ratios is compared to an empirical fitting to give the saturated O2 levels. Measuring this accurately by reflection is hard, the paper reads as a failure (“presents challenges”), but heart rate is easier than oxygen saturation.


I’m writing this half as a filler post and half because I’ve met a lot of people who are using bad ways to organize their pdfs.

For academics or anyone who needs to organize papers, I would strongly recommend using Mendeley. It’s basically a booru for pdfs, and it has good automatic data entry as well. You can upload and access your papers, it automatically scrapes the citation info and generally works well. By adding articles to it every time you read a new one, it lets you search much more effectively for claims that you remember someone made but have no idea where they came from. You can also organize ebooks this way.

A worry that discourages me from any cloud product is that there may be no way to export data if it isn’t supported any more. I’m taking that risk in this case.

Hand dynamometer-part 2

I carved handles out of wood and mounted the strain sensors in it.

Gripping it as hard as I can. Was interesting to see grip strength fail and then increase again when I redoubled my efforts.

Seems to be a working, if low quality dynamometer. If I was to redo this I would build more around the grip and possible use different strain sensors. I might measure the effects of irraditation (tensing other muscles in this context) on grip strength later.

HX711 – Dynamometer part 1

Grip strength can be used as a measure of overtraining.

There are ADC + strain gauge meters on ebay for hobby bodyweight scales (HX711) that should be good for measuring up to around 200kgs. I ordered one and plan to put the gauges between a pair of half cylinders of wood to measure grip strength.

The HX711 can communicate with microcontrollers with a 2 wire interface like I2C. I’ve gotten this working with the Nucleo and tested it by having the Nucleo output a sin wave and reading the voltage that the HX711 measured.

project stuff here, remember that all the Nucleo stuff is compiled using the mbed compiler

Voltage measured by the HX711. Output is in two’s complement, which is why the sin wave is split between top and bottom. You can see the quantization in the DACs output because there’s a minimum 64 fold amplification for the HX711. This means that even a tiny voltage swing will saturate the output.

Galvinic Skin Response and Hand Temperature

Two biofeedback sensors I can probably get working faster than the EEG are hand temperature and galvinic skin response. Hand temperature biofeedback is mostly used to train relaxation. Adrenaline restricts bloodflow to the skin and hands, so by training yourself to warm your hands you can learn to reduce adrenaline levels. Galvinic skin response is similar. People sweat more when nervous, filling sweat ducts with sweat. This is most pronounced on the hands and feet. Sweating reduces skin resistance by providing a conductive channel into the skin. This effect happens in seconds, and is used in polygraphs to detect lies.

For the most part, the resistance inside the body is low enough not to matter when measuring galvinic skin response. The simplest way to measure skin resistance is to put a current through two electrodes in contact with the skin and measure the voltage difference. This is usually done with electrodes on the index and ring fingers.

(For much more detail on measuring galvinic skin response, see Electrodermal Activity by Wolfram Boucsein)

While high temperature measurements usually use thermocouples, the easiest way to measure hand temperature is by using thermistors. The thermistors linked go between about 80k-100k Ohms around 70-100F. They are incredibly small, which gives them really fast response times and makes it easy to keep them around skin temperature.

For measuring each of these resistances, I constructed voltage bridges with instrumentation amplifiers to increase the voltage range. I then used the integrated ADCs in the Nucleo microcontroller I have to measure the voltage.

Set up the voltage bridge with R3/R4 to be a bit below the lowest voltage between R1/R5. Select gain resistor so that Vout is below 3.3V when R1 at its highest. This setup can be used with both GSR and hand temp, but will require different resistors. GSR would probably benefit with variable resistors to set gain and comparison voltage.

See for example which reads the ADC 10 times a second and communicates it to a python program on a host which plots the output.

Plot of voltage measured for thermistor as I grabbed an icepack at t=50 and t=110.
Voltage for skin resistance, again grabbing an icepack at T=220

Like the EEG project, actually having a wearable probe is difficult. For GSR, I used the following copper coils:

I also tried mounting the thermistors in sections of pipe which I could use as GSR electrodes. While it looks neat, I think it will require rings which fit better.