Example code to create a heartbeat sensor using the Si1146 on Silicon Lab's Biometrics expansion board for the Wonder Gecko

Dependencies:   EFM32_SegmentLCD Si114x mbed

main.cpp

Committer:
Sissors
Date:
2015-08-25
Revision:
1:b2b2924c3c48
Parent:
0:f3705ec14cf0

File content as of revision 1:b2b2924c3c48:

/* 
Heart rate example for the SiLabs biometrics board using the Si1146

Since their own example code is all hidden behind precompiled libraries, here an 
example which is actually useful :D. Take into account this is an example, I just screwed
around a bit and observed some output waveforms to make it work reasonable, there are
for sure better ways to implement this.

User manual:
If the Gecko symbol turns on on the LCD it is connected to the sensor
Place your finger on the sensor. In the biometrics board manual it is explained how,
but you can also try until it works properly. You don't want to use the extreme tip of your
finger, but a bit further back.
The battery indicator will flash briefly when a beat is detected. 

Every beat it re-calculates your heartbeat using the time of the previous beat, since no
filtering happens here, it can jump around a bit, but this should be limitted.

And just to be sure since we can never overestimate human stupidity: This is not a medical tool...


Todo: 
1. Get rid of my hardcoded value used as threshold
2. Measure PO2
*/


#include "mbed.h"
#include "Si114x.h"
#include "EFM32_SegmentLCD.h"


DigitalOut myled(LED1);
silabs::EFM32_SegmentLCD segmentDisplay;
        

int main() {
    segmentDisplay.AllOff();
    Si114x sensor(PD6, PD7);
    while(sensor.verifyConnection() != 1);
    segmentDisplay.Symbol(LCD_SYMBOL_GECKO, 1);
    
    int curval;
    int prevval = 0;
    int mvingavg[3] = {0};
    int sum;
    int prevtime = 0;
    int timesincelast;
    float abssum;
    float abssum_iir = 0.0f;
    
    Timer timey;    
    timey.start();
    while(1) {
        curval=sensor.getProximity(2);      //We use visible light, seems to work alot better than IR
        
        //Three times moving average of the diff of the output
        mvingavg[2] = mvingavg[1];
        mvingavg[1] = mvingavg[0];
        mvingavg[0] = curval - prevval;
        sum = mvingavg[2] + mvingavg[1] + mvingavg[0];
        
        //Float val for abs(sum) to calculate threshold dynamically
        abssum = (float)abs(sum);
        abssum_iir = abssum_iir * 0.99f + abssum * 0.01f;
        
        //Now we know the 'average' absolute 'noise' ( plus some part of the heartbeat)
        //We multiply this by four (yes randomly chosen) and use it as threshold for heartbeat
        //Possibly this is too much if you are really excited, but haven't been excited enough to check this
        if (sum < (int)(-4.0f * abssum_iir)) {
            segmentDisplay.Battery(4);
            timesincelast = timey.read_ms() - prevtime;
            if (timesincelast > 250) {
                uint32_t hearthrate = 60000 / timesincelast;
                segmentDisplay.Number(hearthrate);
                prevtime = timey.read_ms();
            }
        }
        else {
            segmentDisplay.Battery(0);
        }
        
        prevval = curval;
    
}
    
}